+/*
+ * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+
+ Change History (most recent first):
+
+$Log: mDNSEmbeddedAPI.h,v $
+Revision 1.114.2.9 2004/04/22 03:17:35 cheshire
+Fix use of "struct __attribute__((__packed__))" so it only applies on GCC >= 2.9
+
+Revision 1.114.2.8 2004/03/30 06:55:37 cheshire
+Gave name to anonymous struct, to avoid errors on certain compilers.
+(Thanks to ramaprasad.kr@hp.com for reporting this.)
+
+Revision 1.114.2.7 2004/03/09 02:31:27 cheshire
+Remove erroneous underscore in 'packed_struct' (makes no difference now, but might in future)
+
+Revision 1.114.2.6 2004/03/02 02:55:25 cheshire
+<rdar://problem/3549576> Properly support "_services._dns-sd._udp" meta-queries
+
+Revision 1.114.2.5 2004/02/18 23:35:17 cheshire
+<rdar://problem/3488559>: Hard code domain enumeration functions to return ".local" only
+Also make mDNS_StopGetDomains() a no-op too, so that we don't get warning messages in syslog
+
+Revision 1.114.2.4 2004/01/28 23:29:20 cheshire
+Fix structure packing (only affects third-party Darwin developers)
+
+Revision 1.114.2.3 2003/12/05 00:03:34 cheshire
+<rdar://problem/3487869> Use buffer size MAX_ESCAPED_DOMAIN_NAME instead of 256
+
+Revision 1.114.2.2 2003/12/04 23:30:00 cheshire
+Add "#define MAX_ESCAPED_DOMAIN_NAME 1005", needed for Posix folder to build
+
+Revision 1.114.2.1 2003/12/03 11:07:58 cheshire
+<rdar://problem/3457718>: Stop and start of a service uses old ip address (with old port number)
+
+Revision 1.114 2003/08/29 19:44:15 cheshire
+<rdar://problem/3400967> Traffic reduction: Eliminate synchronized QUs when a new service appears
+1. Use m->RandomQueryDelay to impose a random delay in the range 0-500ms on queries
+ that already have at least one unique answer in the cache
+2. For these queries, go straight to QM, skipping QU
+
+Revision 1.113 2003/08/21 19:31:58 cheshire
+Cosmetic: Swap order of fields
+
+Revision 1.112 2003/08/21 19:27:36 cheshire
+<rdar://problem/3387878> Traffic reduction: No need to announce record for longer than TTL
+
+Revision 1.111 2003/08/21 02:21:50 cheshire
+<rdar://problem/3386473> Efficiency: Reduce repeated queries
+
+Revision 1.110 2003/08/20 23:39:31 cheshire
+<rdar://problem/3344098> Review syslog messages, and remove as appropriate
+
+Revision 1.109 2003/08/19 22:24:10 cheshire
+Comment change
+
+Revision 1.108 2003/08/19 22:20:00 cheshire
+<rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
+More minor refinements
+
+Revision 1.107 2003/08/19 06:48:25 cheshire
+<rdar://problem/3376552> Guard against excessive record updates
+Each record starts with 10 UpdateCredits.
+Every update consumes one UpdateCredit.
+UpdateCredits are replenished at a rate of one one per minute, up to a maximum of 10.
+As the number of UpdateCredits declines, the number of announcements is similarly scaled back.
+When fewer than 5 UpdateCredits remain, the first announcement is also delayed by an increasing amount.
+
+Revision 1.106 2003/08/19 04:49:28 cheshire
+<rdar://problem/3368159> Interaction between v4, v6 and dual-stack hosts not working quite right
+1. A dual-stack host should only suppress its own query if it sees the same query from other hosts on BOTH IPv4 and IPv6.
+2. When we see the first v4 (or first v6) member of a group, we re-trigger questions and probes on that interface.
+3. When we see the last v4 (or v6) member of a group go away, we revalidate all the records received on that interface.
+
+Revision 1.105 2003/08/19 02:33:37 cheshire
+Update comments
+
+Revision 1.104 2003/08/19 02:31:11 cheshire
+<rdar://problem/3378386> mDNSResponder overenthusiastic with final expiration queries
+Final expiration queries now only mark the question for sending on the particular interface
+pertaining to the record that's expiring.
+
+Revision 1.103 2003/08/18 19:05:44 cheshire
+<rdar://problem/3382423> UpdateRecord not working right
+Added "newrdlength" field to hold new length of updated rdata
+
+Revision 1.102 2003/08/16 03:39:00 cheshire
+<rdar://problem/3338440> InterfaceID -1 indicates "local only"
+
+Revision 1.101 2003/08/15 20:16:02 cheshire
+<rdar://problem/3366590> mDNSResponder takes too much RPRVT
+We want to avoid touching the rdata pages, so we don't page them in.
+1. RDLength was stored with the rdata, which meant touching the page just to find the length.
+ Moved this from the RData to the ResourceRecord object.
+2. To avoid unnecessarily touching the rdata just to compare it,
+ compute a hash of the rdata and store the hash in the ResourceRecord object.
+
+Revision 1.100 2003/08/14 19:29:04 cheshire
+<rdar://problem/3378473> Include cache records in SIGINFO output
+Moved declarations of DNSTypeName() and GetRRDisplayString to mDNSEmbeddedAPI.h so daemon.c can use them
+
+Revision 1.99 2003/08/14 02:17:05 cheshire
+<rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
+
+Revision 1.98 2003/08/12 19:56:23 cheshire
+Update to APSL 2.0
+
+Revision 1.97 2003/08/12 14:59:27 cheshire
+<rdar://problem/3374490> Rate-limiting blocks some legitimate responses
+When setting LastMCTime also record LastMCInterface. When checking LastMCTime to determine
+whether to suppress the response, also check LastMCInterface to see if it matches.
+
+Revision 1.96 2003/08/12 13:57:04 cheshire
+<rdar://problem/3323817> Improve cache performance
+Changed the number of hash table slots from 37 to 499
+
+Revision 1.95 2003/08/09 00:55:02 cheshire
+<rdar://problem/3366553> mDNSResponder is taking 20-30% of the CPU
+Don't scan the whole cache after every packet.
+
+Revision 1.94 2003/08/09 00:35:29 cheshire
+
+Revision 1.93 2003/08/08 18:55:48 cheshire
+<rdar://problem/3370365> Guard against time going backwards
+
+Revision 1.92 2003/08/08 18:36:04 cheshire
+<rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug
+
+Revision 1.91 2003/08/06 21:33:39 cheshire
+Fix compiler warnings on PocketPC 2003 (Windows CE)
+
+Revision 1.90 2003/08/06 20:30:17 cheshire
+Add structure definition for rdataMX (not currently used, but good to have it for completeness)
+
+Revision 1.89 2003/08/06 18:58:19 cheshire
+Update comments
+
+Revision 1.88 2003/07/24 23:45:44 cheshire
+To eliminate compiler warnings, changed definition of mDNSBool from
+"unsigned char" to "int", since "int" is in fact truly the type that C uses
+for the result of comparison operators (a<b) and logical operators (a||b)
+
+Revision 1.87 2003/07/22 23:57:20 cheshire
+Move platform-layer function prototypes from mDNSEmbeddedAPI.h to mDNSPlatformFunctions.h where they belong
+
+Revision 1.86 2003/07/20 03:52:02 ksekar
+Bug #: <rdar://problem/3320722>: Feature: New Rendezvous APIs (#7875) (mDNSResponder component)
+Added error type for incompatibility between daemon and client versions
+
+Revision 1.85 2003/07/19 03:23:13 cheshire
+<rdar://problem/2986147> mDNSResponder needs to receive and cache larger records
+
+Revision 1.84 2003/07/18 23:52:12 cheshire
+To improve consistency of field naming, global search-and-replace:
+NextProbeTime -> NextScheduledProbe
+NextResponseTime -> NextScheduledResponse
+
+Revision 1.83 2003/07/18 00:29:59 cheshire
+<rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
+
+Revision 1.82 2003/07/17 17:35:04 cheshire
+<rdar://problem/3325583> Rate-limit responses, to guard against packet flooding
+
+Revision 1.81 2003/07/16 05:01:36 cheshire
+Add fields 'LargeAnswers' and 'ExpectUnicastResponse' in preparation for
+<rdar://problem/3315761> Need to implement "unicast response" request, using top bit of qclass
+
+Revision 1.80 2003/07/15 01:55:12 cheshire
+<rdar://problem/3315777> Need to implement service registration with subtypes
+
+Revision 1.79 2003/07/13 02:28:00 cheshire
+<rdar://problem/3325166> SendResponses didn't all its responses
+Delete all references to RRInterfaceActive -- it's now superfluous
+
+Revision 1.78 2003/07/13 01:47:53 cheshire
+Fix one error and one warning in the Windows build
+
+Revision 1.77 2003/07/11 01:32:38 cheshire
+Syntactic cleanup (no change to funcationality): Now that we only have one host name,
+rename field "hostname1" to "hostname", and field "RR_A1" to "RR_A".
+
+Revision 1.76 2003/07/11 01:28:00 cheshire
+<rdar://problem/3161289> No more local.arpa
+
+Revision 1.75 2003/07/02 21:19:45 cheshire
+<rdar://problem/3313413> Update copyright notices, etc., in source code comments
+
+Revision 1.74 2003/07/02 02:41:23 cheshire
+<rdar://problem/2986146> mDNSResponder needs to start with a smaller cache and then grow it as needed
+
+Revision 1.73 2003/06/10 04:24:39 cheshire
+<rdar://problem/3283637> React when we observe other people query unsuccessfully for a record that's in our cache
+Some additional refinements:
+Don't try to do this for unicast-response queries
+better tracking of Qs and KAs in multi-packet KA lists
+
+Revision 1.72 2003/06/10 01:46:27 cheshire
+Add better comments explaining how these data structures are intended to be used from the client layer
+
+Revision 1.71 2003/06/07 06:45:05 cheshire
+<rdar://problem/3283666> No need for multiple machines to all be sending the same queries
+
+Revision 1.70 2003/06/07 04:50:53 cheshire
+<rdar://problem/3283637> React when we observe other people query unsuccessfully for a record that's in our cache
+
+Revision 1.69 2003/06/07 04:22:17 cheshire
+Add MsgBuffer for error log and debug messages
+
+Revision 1.68 2003/06/07 01:46:38 cheshire
+<rdar://problem/3283540> When query produces zero results, call mDNS_Reconfirm() on any antecedent records
+
+Revision 1.67 2003/06/07 01:22:14 cheshire
+<rdar://problem/3283516> mDNSResponder needs an mDNS_Reconfirm() function
+
+Revision 1.66 2003/06/07 00:59:43 cheshire
+<rdar://problem/3283454> Need some randomness to spread queries on the network
+
+Revision 1.65 2003/06/06 21:41:11 cheshire
+For consistency, mDNS_StopQuery() should return an mStatus result, just like all the other mDNSCore routines
+
+Revision 1.64 2003/06/06 21:38:55 cheshire
+Renamed 'NewData' as 'FreshData' (The data may not be new data, just a refresh of data that we
+already had in our cache. This refreshes our TTL on the data, but the data itself stays the same.)
+
+Revision 1.63 2003/06/06 17:20:14 cheshire
+For clarity, rename question fields name/rrtype/rrclass as qname/qtype/qclass
+(Global search-and-replace; no functional change to code execution.)
+
+Revision 1.62 2003/06/04 01:25:33 cheshire
+<rdar://problem/3274950> Cannot perform multi-packet known-answer suppression messages
+Display time interval between first and subsequent queries
+
+Revision 1.61 2003/06/03 05:02:16 cheshire
+<rdar://problem/3277080> Duplicate registrations not handled as efficiently as they should be
+
+Revision 1.60 2003/05/31 00:09:49 cheshire
+<rdar://problem/3274862> Add ability to discover what services are on a network
+
+Revision 1.59 2003/05/29 06:11:35 cheshire
+<rdar://problem/3272214>: Report if there appear to be too many "Resolve" callbacks
+
+Revision 1.58 2003/05/29 05:48:06 cheshire
+Minor fix for when generating printf warnings: mDNS_snprintf arguments are now 3,4
+
+Revision 1.57 2003/05/26 03:21:27 cheshire
+Tidy up address structure naming:
+mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
+mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
+mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
+
+Revision 1.56 2003/05/26 03:01:27 cheshire
+<rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
+
+Revision 1.55 2003/05/26 00:47:30 cheshire
+Comment clarification
+
+Revision 1.54 2003/05/24 16:39:48 cheshire
+<rdar://problem/3268631> SendResponses also needs to handle multihoming better
+
+Revision 1.53 2003/05/23 02:15:37 cheshire
+Fixed misleading use of the term "duplicate suppression" where it should have
+said "known answer suppression". (Duplicate answer suppression is something
+different, and duplicate question suppression is yet another thing, so the use
+of the completely vague term "duplicate suppression" was particularly bad.)
+
+Revision 1.52 2003/05/22 02:29:22 cheshire
+<rdar://problem/2984918> SendQueries needs to handle multihoming better
+Complete rewrite of SendQueries. Works much better now :-)
+
+Revision 1.51 2003/05/21 20:14:55 cheshire
+Fix comments and warnings
+
+Revision 1.50 2003/05/14 07:08:36 cheshire
+<rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
+Previously, when there was any network configuration change, mDNSResponder
+would tear down the entire list of active interfaces and start again.
+That was very disruptive, and caused the entire cache to be flushed,
+and caused lots of extra network traffic. Now it only removes interfaces
+that have really gone, and only adds new ones that weren't there before.
+
+Revision 1.49 2003/05/07 01:49:36 cheshire
+Remove "const" in ConstructServiceName prototype
+
+Revision 1.48 2003/05/07 00:18:44 cheshire
+Fix typo: "kDNSQClass_Mask" should be "kDNSClass_Mask"
+
+Revision 1.47 2003/05/06 00:00:46 cheshire
+<rdar://problem/3248914> Rationalize naming of domainname manipulation functions
+
+Revision 1.46 2003/04/30 20:39:09 cheshire
+Add comment
+
+Revision 1.45 2003/04/29 00:40:50 cheshire
+Fix compiler warnings
+
+Revision 1.44 2003/04/26 02:41:56 cheshire
+<rdar://problem/3241281> Change timenow from a local variable to a structure member
+
+Revision 1.43 2003/04/25 01:45:56 cheshire
+<rdar://problem/3240002> mDNS_RegisterNoSuchService needs to include a host name
+
+Revision 1.42 2003/04/15 20:58:31 jgraessl
+
+Bug #: 3229014
+Added a hash to lookup records in the cache.
+
+Revision 1.41 2003/04/15 18:09:13 jgraessl
+
+Bug #: 3228892
+Reviewed by: Stuart Cheshire
+Added code to keep track of when the next cache item will expire so we can
+call TidyRRCache only when necessary.
+
+Revision 1.40 2003/03/29 01:55:19 cheshire
+<rdar://problem/3212360> mDNSResponder sometimes suffers false self-conflicts when it sees its own packets
+Solution: Major cleanup of packet timing and conflict handling rules
+
+Revision 1.39 2003/03/27 03:30:55 cheshire
+<rdar://problem/3210018> Name conflicts not handled properly, resulting in memory corruption, and eventual crash
+Problem was that HostNameCallback() was calling mDNS_DeregisterInterface(), which is not safe in a callback
+Fixes:
+1. Make mDNS_DeregisterInterface() safe to call from a callback
+2. Make HostNameCallback() use mDNS_DeadvertiseInterface() instead
+ (it never really needed to deregister the interface at all)
+
+Revision 1.38 2003/03/15 04:40:36 cheshire
+Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
+
+Revision 1.37 2003/03/14 21:34:11 cheshire
+<rdar://problem/3176950> Can't setup and print to Lexmark PS printers via Airport Extreme
+Increase size of cache rdata from 512 to 768
+
+Revision 1.36 2003/03/05 03:38:35 cheshire
+Bug #: 3185731 Bogus error message in console: died or deallocated, but no record of client can be found!
+Fixed by leaving client in list after conflict, until client explicitly deallocates
+
+Revision 1.35 2003/02/21 02:47:54 cheshire
+Bug #: 3099194 mDNSResponder needs performance improvements
+Several places in the code were calling CacheRRActive(), which searched the entire
+question list every time, to see if this cache resource record answers any question.
+Instead, we now have a field "CRActiveQuestion" in the resource record structure
+
+Revision 1.34 2003/02/21 01:54:08 cheshire
+Bug #: 3099194 mDNSResponder needs performance improvements
+Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
+
+Revision 1.33 2003/02/20 06:48:32 cheshire
+Bug #: 3169535 Xserve RAID needs to do interface-specific registrations
+Reviewed by: Josh Graessley, Bob Bradley
+
+Revision 1.32 2003/01/31 03:35:59 cheshire
+Bug #: 3147097 mDNSResponder sometimes fails to find the correct results
+When there were *two* active questions in the list, they were incorrectly
+finding *each other* and *both* being marked as duplicates of another question
+
+Revision 1.31 2003/01/29 02:46:37 cheshire
+Fix for IPv6:
+A physical interface is identified solely by its InterfaceID (not by IP and type).
+On a given InterfaceID, mDNSCore may send both v4 and v6 multicasts.
+In cases where the requested outbound protocol (v4 or v6) is not supported on
+that InterfaceID, the platform support layer should simply discard that packet.
+
+Revision 1.30 2003/01/29 01:47:08 cheshire
+Rename 'Active' to 'CRActive' or 'InterfaceActive' for improved clarity
+
+Revision 1.29 2003/01/28 05:23:43 cheshire
+Bug #: 3147097 mDNSResponder sometimes fails to find the correct results
+Add 'Active' flag for interfaces
+
+Revision 1.28 2003/01/28 01:35:56 cheshire
+Revise comment about ThisQInterval to reflect new semantics
+
+Revision 1.27 2003/01/13 23:49:42 jgraessl
+Merged changes for the following fixes in to top of tree:
+3086540 computer name changes not handled properly
+3124348 service name changes are not properly handled
+3124352 announcements sent in pairs, failing chattiness test
+
+Revision 1.26 2002/12/23 22:13:28 jgraessl
+
+Reviewed by: Stuart Cheshire
+Initial IPv6 support for mDNSResponder.
+
+Revision 1.25 2002/09/21 20:44:49 zarzycki
+Added APSL info
+
+Revision 1.24 2002/09/19 23:47:35 cheshire
+Added mDNS_RegisterNoSuchService() function for assertion of non-existence
+of a particular named service
+
+Revision 1.23 2002/09/19 21:25:34 cheshire
+mDNS_snprintf() doesn't need to be in a separate file
+
+Revision 1.22 2002/09/19 04:20:43 cheshire
+Remove high-ascii characters that confuse some systems
+
+Revision 1.21 2002/09/17 01:06:35 cheshire
+Change mDNS_AdvertiseLocalAddresses to be a parameter to mDNS_Init()
+
+Revision 1.20 2002/09/16 18:41:41 cheshire
+Merge in license terms from Quinn's copy, in preparation for Darwin release
+
+*/
+
+#ifndef __mDNSClientAPI_h
+#define __mDNSClientAPI_h
+
+#include <stdarg.h> // stdarg.h is required for for va_list support for the mDNS_vsnprintf declaration
+#include "mDNSDebug.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+// ***************************************************************************
+// Function scope indicators
+
+// If you see "mDNSlocal" before a function name in a C file, it means the function is not callable outside this file
+#ifndef mDNSlocal
+#define mDNSlocal static
+#endif
+// If you see "mDNSexport" before a symbol in a C file, it means the symbol is exported for use by clients
+// For every "mDNSexport" in a C file, there needs to be a corresponding "extern" declaration in some header file
+// (When a C file #includes a header file, the "extern" declarations tell the compiler:
+// "This symbol exists -- but not necessarily in this C file.")
+#ifndef mDNSexport
+#define mDNSexport
+#endif
+
+// ***************************************************************************
+// Structure packing macro
+
+// If we're not using GNUC, it's not fatal.
+// Most compilers naturally pack the on-the-wire structures correctly anyway, so a plain "struct" is usually fine.
+// In the event that structures are not packed correctly, mDNS_Init() will detect this and report an error, so the
+// developer will know what's wrong, and can investigate what needs to be done on that compiler to provide proper packing.
+#ifndef packedstruct
+ #if ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 9)))
+ #define packedstruct struct __attribute__((__packed__))
+ #define packedunion union __attribute__((__packed__))
+ #else
+ #define packedstruct struct
+ #define packedunion union
+ #endif
+#endif
+
+// ***************************************************************************
+#if 0
+#pragma mark - DNS Resource Record class and type constants
+#endif
+
+typedef enum // From RFC 1035
+ {
+ kDNSClass_IN = 1, // Internet
+ kDNSClass_CS = 2, // CSNET
+ kDNSClass_CH = 3, // CHAOS
+ kDNSClass_HS = 4, // Hesiod
+ kDNSClass_NONE = 254, // Used in DNS UPDATE [RFC 2136]
+
+ kDNSClass_Mask = 0x7FFF,// Multicast DNS uses the bottom 15 bits to identify the record class...
+ kDNSClass_UniqueRRSet = 0x8000,// ... and the top bit indicates that all other cached records are now invalid
+
+ kDNSQClass_ANY = 255, // Not a DNS class, but a DNS query class, meaning "all classes"
+ kDNSQClass_UnicastResponse = 0x8000 // Top bit set in a question means "unicast response acceptable"
+ } DNS_ClassValues;
+
+typedef enum // From RFC 1035
+ {
+ kDNSType_A = 1, // 1 Address
+ kDNSType_NS, // 2 Name Server
+ kDNSType_MD, // 3 Mail Destination
+ kDNSType_MF, // 4 Mail Forwarder
+ kDNSType_CNAME, // 5 Canonical Name
+ kDNSType_SOA, // 6 Start of Authority
+ kDNSType_MB, // 7 Mailbox
+ kDNSType_MG, // 8 Mail Group
+ kDNSType_MR, // 9 Mail Rename
+ kDNSType_NULL, // 10 NULL RR
+ kDNSType_WKS, // 11 Well-known-service
+ kDNSType_PTR, // 12 Domain name pointer
+ kDNSType_HINFO, // 13 Host information
+ kDNSType_MINFO, // 14 Mailbox information
+ kDNSType_MX, // 15 Mail Exchanger
+ kDNSType_TXT, // 16 Arbitrary text string
+
+ kDNSType_AAAA = 28, // 28 IPv6 address
+ kDNSType_SRV = 33, // 33 Service record
+
+ kDNSQType_ANY = 255 // Not a DNS type, but a DNS query type, meaning "all types"
+ } DNS_TypeValues;
+
+// ***************************************************************************
+#if 0
+#pragma mark - Simple types
+#endif
+
+// mDNS defines its own names for these common types to simplify portability across
+// multiple platforms that may each have their own (different) names for these types.
+typedef int mDNSBool;
+typedef signed char mDNSs8;
+typedef unsigned char mDNSu8;
+typedef signed short mDNSs16;
+typedef unsigned short mDNSu16;
+#if _LP64
+typedef signed int mDNSs32;
+typedef unsigned int mDNSu32;
+#else
+typedef signed long mDNSs32;
+typedef unsigned long mDNSu32;
+#endif
+
+// To enforce useful type checking, we make mDNSInterfaceID be a pointer to a dummy struct
+// This way, mDNSInterfaceIDs can be assigned, and compared with each other, but not with other types
+// Declaring the type to be the typical generic "void *" would lack this type checking
+typedef struct mDNSInterfaceID_dummystruct { void *dummy; } *mDNSInterfaceID;
+
+// These types are for opaque two- and four-byte identifiers.
+// The "NotAnInteger" fields of the unions allow the value to be conveniently passed around in a
+// register for the sake of efficiency, and compared for equality or inequality, but don't forget --
+// just because it is in a register doesn't mean it is an integer. Operations like greater than,
+// less than, add, multiply, increment, decrement, etc., are undefined for opaque identifiers,
+// and if you make the mistake of trying to do those using the NotAnInteger field, then you'll
+// find you get code that doesn't work consistently on big-endian and little-endian machines.
+typedef packedunion { mDNSu8 b[2]; mDNSu16 NotAnInteger; } mDNSOpaque16;
+typedef packedunion { mDNSu8 b[4]; mDNSu32 NotAnInteger; } mDNSOpaque32;
+typedef packedunion { mDNSu8 b[16]; mDNSu16 w[8]; mDNSu32 l[4]; } mDNSOpaque128;
+
+typedef mDNSOpaque16 mDNSIPPort; // An IP port is a two-byte opaque identifier (not an integer)
+typedef mDNSOpaque32 mDNSv4Addr; // An IP address is a four-byte opaque identifier (not an integer)
+typedef mDNSOpaque128 mDNSv6Addr; // An IPv6 address is a 16-byte opaque identifier (not an integer)
+
+enum
+ {
+ mDNSAddrType_None = 0,
+ mDNSAddrType_IPv4 = 4,
+ mDNSAddrType_IPv6 = 6,
+ mDNSAddrType_Unknown = ~0 // Special marker value used in known answer list recording
+ };
+
+typedef struct
+ {
+ mDNSs32 type;
+ union { mDNSv6Addr v6; mDNSv4Addr v4; } ip;
+ } mDNSAddr;
+
+enum { mDNSfalse = 0, mDNStrue = 1 };
+
+#define mDNSNULL 0L
+
+enum
+ {
+ mStatus_Waiting = 1,
+ mStatus_NoError = 0,
+
+ // mDNS return values are in the range FFFE FF00 (-65792) to FFFE FFFF (-65537)
+ // The top end of the range (FFFE FFFF) is used for error codes;
+ // the bottom end of the range (FFFE FF00) is used for non-error values;
+
+ // Error codes:
+ mStatus_UnknownErr = -65537, // 0xFFFE FFFF
+ mStatus_NoSuchNameErr = -65538,
+ mStatus_NoMemoryErr = -65539,
+ mStatus_BadParamErr = -65540,
+ mStatus_BadReferenceErr = -65541,
+ mStatus_BadStateErr = -65542,
+ mStatus_BadFlagsErr = -65543,
+ mStatus_UnsupportedErr = -65544,
+ mStatus_NotInitializedErr = -65545,
+ mStatus_NoCache = -65546,
+ mStatus_AlreadyRegistered = -65547,
+ mStatus_NameConflict = -65548,
+ mStatus_Invalid = -65549,
+ // = -65550,
+ mStatus_Incompatible = -65551,
+ mStatus_BadInterfaceErr = -65552,
+
+ // -65553 - -65789 currently unused
+
+ // Non-error values:
+ mStatus_GrowCache = -65790,
+ mStatus_ConfigChanged = -65791,
+ mStatus_MemFree = -65792 // 0xFFFE FF00
+ };
+
+typedef mDNSs32 mStatus;
+
+// RFC 1034/1035 specify that a domain label consists of a length byte plus up to 63 characters
+#define MAX_DOMAIN_LABEL 63
+typedef struct { mDNSu8 c[ 64]; } domainlabel; // One label: length byte and up to 63 characters
+
+// RFC 1034/1035 specify that a domain name, including length bytes, data bytes, and terminating zero, may be up to 255 bytes long
+#define MAX_DOMAIN_NAME 255
+typedef struct { mDNSu8 c[256]; } domainname; // Up to 255 bytes of length-prefixed domainlabels
+
+typedef struct { mDNSu8 c[256]; } UTF8str255; // Null-terminated C string
+
+// The longest legal textual form of a DNS name is 1005 bytes, including the C-string terminating NULL at the end.
+// Explanation:
+// When a native domainname object is converted to printable textual form using ConvertDomainNameToCString(),
+// non-printing characters are represented in the conventional DNS way, as '\ddd', where ddd is a three-digit decimal number.
+// The longest legal domain name is 255 bytes, in the form of four labels as shown below:
+// Length byte, 63 data bytes, length byte, 63 data bytes, length byte, 63 data bytes, length byte, 61 data bytes, zero byte.
+// Each label is encoded textually as characters followed by a trailing dot.
+// If every character has to be represented as a four-byte escape sequence, then this makes the maximum textual form four labels
+// plus the C-string terminating NULL as shown below:
+// 63*4+1 + 63*4+1 + 63*4+1 + 61*4+1 + 1 = 1005.
+// Note that MAX_ESCAPED_DOMAIN_LABEL is not normally used: If you're only decoding a single label, escaping is usually not required.
+// It is for domain names, where dots are used as label separators, that proper escaping is vital.
+#define MAX_ESCAPED_DOMAIN_LABEL 254
+#define MAX_ESCAPED_DOMAIN_NAME 1005
+
+// ***************************************************************************
+#if 0
+#pragma mark - Resource Record structures
+#endif
+
+// Authoritative Resource Records:
+// There are four basic types: Shared, Advisory, Unique, Known Unique
+
+// * Shared Resource Records do not have to be unique
+// -- Shared Resource Records are used for DNS-SD service PTRs
+// -- It is okay for several hosts to have RRs with the same name but different RDATA
+// -- We use a random delay on responses to reduce collisions when all the hosts respond to the same query
+// -- These RRs typically have moderately high TTLs (e.g. one hour)
+// -- These records are announced on startup and topology changes for the benefit of passive listeners
+// -- These records send a goodbye packet when deregistering
+//
+// * Advisory Resource Records are like Shared Resource Records, except they don't send a goodbye packet
+//
+// * Unique Resource Records should be unique among hosts within any given mDNS scope
+// -- The majority of Resource Records are of this type
+// -- If two entities on the network have RRs with the same name but different RDATA, this is a conflict
+// -- Responses may be sent immediately, because only one host should be responding to any particular query
+// -- These RRs typically have low TTLs (e.g. ten seconds)
+// -- On startup and after topology changes, a host issues queries to verify uniqueness
+
+// * Known Unique Resource Records are treated like Unique Resource Records, except that mDNS does
+// not have to verify their uniqueness because this is already known by other means (e.g. the RR name
+// is derived from the host's IP or Ethernet address, which is already known to be a unique identifier).
+
+// Summary of properties of different record types:
+// Probe? Does this record type send probes before announcing?
+// Conflict? Does this record type react if we observe an apparent conflict?
+// Goodbye? Does this record type send a goodbye packet on departure?
+//
+// Probe? Conflict? Goodbye? Notes
+// Unregistered Should not appear in any list (sanity check value)
+// Shared No No Yes e.g. Service PTR record
+// Deregistering No No Yes Shared record about to announce its departure and leave the list
+// Advisory No No No
+// Unique Yes Yes No Record intended to be unique -- will probe to verify
+// Verified Yes Yes No Record has completed probing, and is verified unique
+// KnownUnique No Yes No Record is assumed by other means to be unique
+
+// Valid lifecycle of a record:
+// Unregistered -> Shared -> Deregistering -(goodbye)-> Unregistered
+// Unregistered -> Advisory -> Unregistered
+// Unregistered -> Unique -(probe)-> Verified -> Unregistered
+// Unregistered -> KnownUnique -> Unregistered
+
+// Each Authoritative kDNSRecordType has only one bit set. This makes it easy to quickly see if a record
+// is one of a particular set of types simply by performing the appropriate bitwise masking operation.
+
+// Cache Resource Records (received from the network):
+// There are four basic types: Answer, Unique Answer, Additional, Unique Additional
+// Bit 7 (the top bit) of kDNSRecordType is always set for Cache Resource Records; always clear for Authoritative Resource Records
+// Bit 6 (value 0x40) is set for answer records; clear for additional records
+// Bit 5 (value 0x20) is set for records received with the kDNSClass_UniqueRRSet
+
+enum
+ {
+ kDNSRecordTypeUnregistered = 0x00, // Not currently in any list
+ kDNSRecordTypeDeregistering = 0x01, // Shared record about to announce its departure and leave the list
+
+ kDNSRecordTypeUnique = 0x02, // Will become a kDNSRecordTypeVerified when probing is complete
+
+ kDNSRecordTypeAdvisory = 0x04, // Like Shared, but no goodbye packet
+ kDNSRecordTypeShared = 0x08, // Shared means record name does not have to be unique -- use random delay on responses
+ kDNSRecordTypeVerified = 0x10, // Unique means mDNS should check that name is unique (and then send immediate responses)
+ kDNSRecordTypeKnownUnique = 0x20, // Known Unique means mDNS can assume name is unique without checking
+
+ kDNSRecordTypeUniqueMask = (kDNSRecordTypeUnique | kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique),
+ kDNSRecordTypeActiveMask = (kDNSRecordTypeAdvisory | kDNSRecordTypeShared | kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique),
+
+ kDNSRecordTypePacketAdd = 0x80, // Received in the Additional Section of a DNS Response
+ kDNSRecordTypePacketAddUnique = 0xA0, // Received in the Additional Section of a DNS Response with kDNSClass_UniqueRRSet set
+ kDNSRecordTypePacketAns = 0xC0, // Received in the Answer Section of a DNS Response
+ kDNSRecordTypePacketAnsUnique = 0xE0, // Received in the Answer Section of a DNS Response with kDNSClass_UniqueRRSet set
+
+ kDNSRecordTypePacketAnsMask = 0x40, // True for PacketAns and PacketAnsUnique
+ kDNSRecordTypePacketUniqueMask = 0x20 // True for PacketAddUnique and PacketAnsUnique
+ };
+
+typedef packedstruct { mDNSu16 priority; mDNSu16 weight; mDNSIPPort port; domainname target; } rdataSRV;
+typedef packedstruct { mDNSu16 preference; domainname exchange; } rdataMX;
+
+// StandardAuthRDSize is 264 (256+8), which is large enough to hold a maximum-sized SRV record
+// MaximumRDSize is 8K the absolute maximum we support (at least for now)
+#define StandardAuthRDSize 264
+#define MaximumRDSize 8192
+
+// InlineCacheRDSize is 64
+// Records received from the network with rdata this size or less have their rdata stored right in the CacheRecord object
+// Records received from the network with rdata larger than this have additional storage allocated for the rdata
+// A quick unscientific sample from a busy network at Apple with lots of machines revealed this:
+// 1461 records in cache
+// 292 were one-byte TXT records
+// 136 were four-byte A records
+// 184 were sixteen-byte AAAA records
+// 780 were various PTR, TXT and SRV records from 12-64 bytes
+// Only 69 records had rdata bigger than 64 bytes
+#define InlineCacheRDSize 64
+
+typedef union
+ {
+ mDNSu8 data[StandardAuthRDSize];
+ mDNSv4Addr ip; // For 'A' record
+ mDNSv6Addr ipv6; // For 'AAAA' record
+ domainname name; // For PTR and CNAME records
+ UTF8str255 txt; // For TXT record
+ rdataSRV srv; // For SRV record
+ rdataMX mx; // For MX record
+ } RDataBody;
+
+typedef struct
+ {
+ mDNSu16 MaxRDLength; // Amount of storage allocated for rdata (usually sizeof(RDataBody))
+ RDataBody u;
+ } RData;
+#define sizeofRDataHeader (sizeof(RData) - sizeof(RDataBody))
+
+typedef struct AuthRecord_struct AuthRecord;
+typedef struct CacheRecord_struct CacheRecord;
+typedef struct ResourceRecord_struct ResourceRecord;
+typedef struct DNSQuestion_struct DNSQuestion;
+typedef struct mDNS_struct mDNS;
+typedef struct mDNS_PlatformSupport_struct mDNS_PlatformSupport;
+
+// Note: Within an mDNSRecordCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Close(), mDNS_Execute()
+typedef void mDNSRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
+
+// Note:
+// Restrictions: An mDNSRecordUpdateCallback may not make any mDNS API calls.
+// The intent of this callback is to allow the client to free memory, if necessary.
+// The internal data structures of the mDNS code may not be in a state where mDNS API calls may be made safely.
+typedef void mDNSRecordUpdateCallback(mDNS *const m, AuthRecord *const rr, RData *OldRData);
+
+struct ResourceRecord_struct
+ {
+ mDNSu8 RecordType; // See enum above
+ mDNSInterfaceID InterfaceID; // Set if this RR is specific to one interface
+ // For records received off the wire, InterfaceID is *always* set to the receiving interface
+ // For our authoritative records, InterfaceID is usually zero, except for those few records
+ // that are interface-specific (e.g. address records, especially linklocal addresses)
+ domainname name;
+ mDNSu16 rrtype;
+ mDNSu16 rrclass;
+ mDNSu32 rroriginalttl; // In seconds
+ mDNSu16 rdlength; // Size of the raw rdata, in bytes
+ mDNSu16 rdestimate; // Upper bound on size of rdata after name compression
+ mDNSu32 namehash; // Name-based (i.e. case insensitive) hash of name
+ mDNSu32 rdatahash; // 32-bit hash of the raw rdata
+ mDNSu32 rdnamehash; // Set if this rdata contains a domain name (e.g. PTR, SRV, CNAME etc.)
+ RData *rdata; // Pointer to storage for this rdata
+ };
+
+struct AuthRecord_struct
+ {
+ // For examples of how to set up this structure for use in mDNS_Register(),
+ // see mDNS_AdvertiseInterface() or mDNS_RegisterService().
+ // Basically, resrec and persistent metadata need to be set up before calling mDNS_Register().
+ // mDNS_SetupResourceRecord() is avaliable as a helper routine to set up most fields to sensible default values for you
+
+ AuthRecord *next; // Next in list; first element of structure for efficiency reasons
+ ResourceRecord resrec;
+
+ // Persistent metadata for Authoritative Records
+ AuthRecord *Additional1; // Recommended additional record to include in response
+ AuthRecord *Additional2; // Another additional
+ AuthRecord *DependentOn; // This record depends on another for its uniqueness checking
+ AuthRecord *RRSet; // This unique record is part of an RRSet
+ mDNSRecordCallback *RecordCallback; // Callback function to call for state changes
+ void *RecordContext; // Context parameter for the callback function
+ mDNSu8 HostTarget; // Set if the target of this record (PTR, CNAME, SRV, etc.) is our host name
+
+ // Transient state for Authoritative Records
+ mDNSu8 Acknowledged; // Set if we've given the success callback to the client
+ mDNSu8 ProbeCount; // Number of probes remaining before this record is valid (kDNSRecordTypeUnique)
+ mDNSu8 AnnounceCount; // Number of announcements remaining (kDNSRecordTypeShared)
+ mDNSu8 IncludeInProbe; // Set if this RR is being put into a probe right now
+ mDNSInterfaceID ImmedAnswer; // Someone on this interface issued a query we need to answer (all-ones for all interfaces)
+ mDNSInterfaceID ImmedAdditional; // Hint that we might want to also send this record, just to be helpful
+ mDNSInterfaceID SendRNow; // The interface this query is being sent on right now
+ mDNSv4Addr v4Requester; // Recent v4 query for this record, or all-ones if more than one recent query
+ mDNSv6Addr v6Requester; // Recent v6 query for this record, or all-ones if more than one recent query
+ AuthRecord *NextResponse; // Link to the next element in the chain of responses to generate
+ const mDNSu8 *NR_AnswerTo; // Set if this record was selected by virtue of being a direct answer to a question
+ AuthRecord *NR_AdditionalTo; // Set if this record was selected by virtue of being additional to another
+ mDNSs32 ThisAPInterval; // In platform time units: Current interval for announce/probe
+ mDNSs32 AnnounceUntil; // In platform time units: Creation time + TTL
+ mDNSs32 LastAPTime; // In platform time units: Last time we sent announcement/probe
+ mDNSs32 LastMCTime; // Last time we multicast this record (used to guard against packet-storm attacks)
+ mDNSInterfaceID LastMCInterface; // Interface this record was multicast on at the time LastMCTime was recorded
+ RData *NewRData; // Set if we are updating this record with new rdata
+ mDNSu16 newrdlength; // ... and the length of the new RData
+ mDNSRecordUpdateCallback *UpdateCallback;
+ mDNSu32 UpdateCredits; // Token-bucket rate limiting of excessive updates
+ mDNSs32 NextUpdateCredit; // Time next token is added to bucket
+ mDNSs32 UpdateBlocked; // Set if update delaying is in effect
+
+ RData rdatastorage; // Normally the storage is right here, except for oversized records
+ // rdatastorage MUST be the last thing in the structure -- when using oversized AuthRecords, extra bytes
+ // are appended after the end of the AuthRecord, logically augmenting the size of the rdatastorage
+ // DO NOT ADD ANY MORE FIELDS HERE
+ };
+
+struct CacheRecord_struct
+ {
+ CacheRecord *next; // Next in list; first element of structure for efficiency reasons
+ ResourceRecord resrec;
+
+ // Transient state for Cache Records
+ CacheRecord *NextInKAList; // Link to the next element in the chain of known answers to send
+ mDNSs32 TimeRcvd; // In platform time units
+ mDNSs32 NextRequiredQuery; // In platform time units
+ mDNSs32 LastUsed; // In platform time units
+ mDNSu32 UseCount; // Number of times this RR has been used to answer a question
+ DNSQuestion *CRActiveQuestion; // Points to an active question referencing this answer
+ mDNSu32 UnansweredQueries; // Number of times we've issued a query for this record without getting an answer
+ mDNSs32 LastUnansweredTime; // In platform time units; last time we incremented UnansweredQueries
+ mDNSu32 MPUnansweredQ; // Multi-packet query handling: Number of times we've seen a query for this record
+ mDNSs32 MPLastUnansweredQT; // Multi-packet query handling: Last time we incremented MPUnansweredQ
+ mDNSu32 MPUnansweredKA; // Multi-packet query handling: Number of times we've seen this record in a KA list
+ mDNSBool MPExpectingKA; // Multi-packet query handling: Set when we increment MPUnansweredQ; allows one KA
+ CacheRecord *NextInCFList; // Set if this is in the list of records we just received with the cache flush bit set
+
+ struct { mDNSu16 MaxRDLength; mDNSu8 data[InlineCacheRDSize]; } rdatastorage; // Storage for small records is right here
+ };
+
+typedef struct
+ {
+ CacheRecord r;
+ mDNSu8 _extradata[MaximumRDSize-InlineCacheRDSize]; // Glue on the necessary number of extra bytes
+ } LargeCacheRecord;
+
+typedef struct NetworkInterfaceInfo_struct NetworkInterfaceInfo;
+
+struct NetworkInterfaceInfo_struct
+ {
+ // Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them.
+ NetworkInterfaceInfo *next;
+
+ mDNSBool InterfaceActive; // InterfaceActive is set if interface is sending & receiving packets
+ // InterfaceActive is clear if interface is here to represent an address with A
+ // and/or AAAA records, but there is already an earlier representative for this
+ // physical interface which will be used for the actual sending & receiving
+ // packets (this status may change as interfaces are added and removed)
+ mDNSBool IPv4Available; // If InterfaceActive, set if v4 available on this InterfaceID
+ mDNSBool IPv6Available; // If InterfaceActive, set if v6 available on this InterfaceID
+
+ // Standard AuthRecords that every Responder host should have (one per active IP address)
+ AuthRecord RR_A; // 'A' or 'AAAA' (address) record for our ".local" name
+ AuthRecord RR_PTR; // PTR (reverse lookup) record
+ AuthRecord RR_HINFO;
+
+ // Client API fields: The client must set up these fields *before* calling mDNS_RegisterInterface()
+ mDNSInterfaceID InterfaceID;
+ mDNSAddr ip;
+ mDNSBool Advertise; // Set Advertise to false if you are only searching on this interface
+ mDNSBool TxAndRx; // Set to false if not sending and receiving packets on this interface
+ };
+
+typedef struct ExtraResourceRecord_struct ExtraResourceRecord;
+struct ExtraResourceRecord_struct
+ {
+ ExtraResourceRecord *next;
+ AuthRecord r;
+ // Note: Add any additional fields *before* the AuthRecord in this structure, not at the end.
+ // In some cases clients can allocate larger chunks of memory and set r->rdata->MaxRDLength to indicate
+ // that this extra memory is available, which would result in any fields after the AuthRecord getting smashed
+ };
+
+// Note: Within an mDNSServiceCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Close(), mDNS_Execute()
+typedef struct ServiceRecordSet_struct ServiceRecordSet;
+typedef void mDNSServiceCallback(mDNS *const m, ServiceRecordSet *const sr, mStatus result);
+struct ServiceRecordSet_struct
+ {
+ // Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them.
+ // No fields need to be set up by the client prior to calling mDNS_RegisterService();
+ // all required data is passed as parameters to that function.
+ mDNSServiceCallback *ServiceCallback;
+ void *ServiceContext;
+ ExtraResourceRecord *Extras; // Optional list of extra AuthRecords attached to this service registration
+ mDNSu32 NumSubTypes;
+ AuthRecord *SubTypes;
+ mDNSBool Conflict; // Set if this record set was forcibly deregistered because of a conflict
+ domainname Host; // Set if this service record does not use the standard target host name
+ AuthRecord RR_ADV; // e.g. _services._dns-sd._udp.local. PTR _printer._tcp.local.
+ AuthRecord RR_PTR; // e.g. _printer._tcp.local. PTR Name._printer._tcp.local.
+ AuthRecord RR_SRV; // e.g. Name._printer._tcp.local. SRV 0 0 port target
+ AuthRecord RR_TXT; // e.g. Name._printer._tcp.local. TXT PrintQueueName
+ // Don't add any fields after AuthRecord RR_TXT.
+ // This is where the implicit extra space goes if we allocate a ServiceRecordSet containing an oversized RR_TXT record
+ };
+
+// ***************************************************************************
+#if 0
+#pragma mark - Question structures
+#endif
+
+// We record the last eight instances of each duplicate query
+// This gives us v4/v6 on each of Ethernet/AirPort and Firewire, and two free slots "for future expansion"
+// If the host has more active interfaces that this it is not fatal -- duplicate question suppression will degrade gracefully.
+// Since we will still remember the last eight, the busiest interfaces will still get the effective duplicate question suppression.
+#define DupSuppressInfoSize 8
+
+typedef struct
+ {
+ mDNSs32 Time;
+ mDNSInterfaceID InterfaceID;
+ mDNSs32 Type; // v4 or v6?
+ } DupSuppressInfo;
+
+// Note: Within an mDNSQuestionCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Close(), mDNS_Execute()
+typedef void mDNSQuestionCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
+struct DNSQuestion_struct
+ {
+ // Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them.
+ DNSQuestion *next;
+ mDNSu32 qnamehash;
+ mDNSs32 LastQTime; // Last scheduled transmission of this Q on *all* applicable interfaces
+ mDNSs32 ThisQInterval; // LastQTime + ThisQInterval is the next scheduled transmission of this Q
+ // ThisQInterval > 0 for an active question;
+ // ThisQInterval = 0 for a suspended question that's still in the list
+ // ThisQInterval = -1 for a cancelled question that's been removed from the list
+ mDNSu32 RecentAnswers; // Number of answers since the last time we sent this query
+ mDNSu32 CurrentAnswers; // Number of records currently in the cache that answer this question
+ mDNSu32 LargeAnswers; // Number of answers with rdata > 1024 bytes
+ mDNSu32 UniqueAnswers; // Number of answers received with kDNSClass_UniqueRRSet bit set
+ DNSQuestion *DuplicateOf;
+ DNSQuestion *NextInDQList;
+ DupSuppressInfo DupSuppress[DupSuppressInfoSize];
+ mDNSInterfaceID SendQNow; // The interface this query is being sent on right now
+ mDNSBool SendOnAll; // Set if we're sending this question on all active interfaces
+ mDNSs32 LastQTxTime; // Last time this Q was sent on one (but not necessarily all) interfaces
+
+ // Client API fields: The client must set up these fields *before* calling mDNS_StartQuery()
+ mDNSInterfaceID InterfaceID; // Non-zero if you want to issue link-local queries only on a single specific IP interface
+ domainname qname;
+ mDNSu16 qtype;
+ mDNSu16 qclass;
+ mDNSQuestionCallback *QuestionCallback;
+ void *QuestionContext;
+ };
+
+typedef struct
+ {
+ // Client API fields: The client must set up name and InterfaceID *before* calling mDNS_StartResolveService()
+ // When the callback is invoked, ip, port, TXTlen and TXTinfo will have been filled in with the results learned from the network.
+ domainname name;
+ mDNSInterfaceID InterfaceID; // ID of the interface the response was received on
+ mDNSAddr ip; // Remote (destination) IP address where this service can be accessed
+ mDNSIPPort port; // Port where this service can be accessed
+ mDNSu16 TXTlen;
+ mDNSu8 TXTinfo[2048]; // Additional demultiplexing information (e.g. LPR queue name)
+ } ServiceInfo;
+
+// Note: Within an mDNSServiceInfoQueryCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Close(), mDNS_Execute()
+typedef struct ServiceInfoQuery_struct ServiceInfoQuery;
+typedef void mDNSServiceInfoQueryCallback(mDNS *const m, ServiceInfoQuery *query);
+struct ServiceInfoQuery_struct
+ {
+ // Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them.
+ // No fields need to be set up by the client prior to calling mDNS_StartResolveService();
+ // all required data is passed as parameters to that function.
+ // The ServiceInfoQuery structure memory is working storage for mDNSCore to discover the requested information
+ // and place it in the ServiceInfo structure. After the client has called mDNS_StopResolveService(), it may
+ // dispose of the ServiceInfoQuery structure while retaining the results in the ServiceInfo structure.
+ DNSQuestion qSRV;
+ DNSQuestion qTXT;
+ DNSQuestion qAv4;
+ DNSQuestion qAv6;
+ mDNSu8 GotSRV;
+ mDNSu8 GotTXT;
+ mDNSu8 GotADD;
+ mDNSu32 Answers;
+ ServiceInfo *info;
+ mDNSServiceInfoQueryCallback *ServiceInfoQueryCallback;
+ void *ServiceInfoQueryContext;
+ };
+
+// ***************************************************************************
+#if 0
+#pragma mark - Main mDNS object, used to hold all the mDNS state
+#endif
+
+typedef void mDNSCallback(mDNS *const m, mStatus result);
+
+#define CACHE_HASH_SLOTS 499
+
+enum
+ {
+ mDNS_KnownBug_PhantomInterfaces = 1
+ };
+
+struct mDNS_struct
+ {
+ // Internal state fields. These hold the main internal state of mDNSCore;
+ // the client layer needn't be concerned with them.
+ // No fields need to be set up by the client prior to calling mDNS_Init();
+ // all required data is passed as parameters to that function.
+
+ mDNS_PlatformSupport *p; // Pointer to platform-specific data of indeterminite size
+ mDNSu32 KnownBugs;
+ mDNSBool AdvertiseLocalAddresses;
+ mStatus mDNSPlatformStatus;
+ mDNSCallback *MainCallback;
+ void *MainContext;
+
+ // For debugging: To catch and report locking failures
+ mDNSu32 mDNS_busy; // Incremented between mDNS_Lock/mDNS_Unlock section
+ mDNSu32 mDNS_reentrancy; // Incremented when calling a client callback
+ mDNSu8 mDNS_shutdown; // Set when we're shutting down, allows us to skip some unnecessary steps
+ mDNSu8 lock_rrcache; // For debugging: Set at times when these lists may not be modified
+ mDNSu8 lock_Questions;
+ mDNSu8 lock_Records;
+ char MsgBuffer[80]; // Temp storage used while building error log messages
+
+ // Task Scheduling variables
+ mDNSs32 timenow; // The time that this particular activation of the mDNS code started
+ mDNSs32 timenow_last; // The time the last time we ran
+ mDNSs32 timenow_adjust; // Correction applied if we ever discover time went backwards
+ mDNSs32 NextScheduledEvent; // Derived from values below
+ mDNSs32 SuppressSending; // Don't send *any* packets during this time
+ mDNSs32 NextCacheCheck; // Next time to refresh cache record before it expires
+ mDNSs32 NextScheduledQuery; // Next time to send query in its exponential backoff sequence
+ mDNSs32 NextScheduledProbe; // Next time to probe for new authoritative record
+ mDNSs32 NextScheduledResponse; // Next time to send authoritative record(s) in responses
+ mDNSs32 ExpectUnicastResponse; // Set when we send a query with the kDNSQClass_UnicastResponse bit set
+ mDNSs32 RandomQueryDelay; // For de-synchronization of query packets on the wire
+ mDNSBool SendDeregistrations; // Set if we need to send deregistrations (immediately)
+ mDNSBool SendImmediateAnswers; // Set if we need to send answers (immediately -- or as soon as SuppressSending clears)
+ mDNSBool SleepState; // Set if we're sleeping (send no more packets)
+
+ // These fields only required for mDNS Searcher...
+ DNSQuestion *Questions; // List of all registered questions, active and inactive
+ DNSQuestion *NewQuestions; // Fresh questions not yet answered from cache
+ DNSQuestion *CurrentQuestion; // Next question about to be examined in AnswerLocalQuestions()
+ DNSQuestion *LocalOnlyQuestions; // Questions with InterfaceID set to ~0 ("local only")
+ DNSQuestion *NewLocalOnlyQuestions; // Fresh local-only questions not yet answered
+ mDNSu32 rrcache_size; // Total number of available cache entries
+ mDNSu32 rrcache_totalused; // Number of cache entries currently occupied
+ mDNSu32 rrcache_active; // Number of cache entries currently occupied by records that answer active questions
+ mDNSu32 rrcache_report;
+ CacheRecord *rrcache_free;
+ CacheRecord *rrcache_hash[CACHE_HASH_SLOTS];
+ CacheRecord **rrcache_tail[CACHE_HASH_SLOTS];
+ mDNSu32 rrcache_used[CACHE_HASH_SLOTS];
+
+ // Fields below only required for mDNS Responder...
+ domainlabel nicelabel; // Rich text label encoded using canonically precomposed UTF-8
+ domainlabel hostlabel; // Conforms to RFC 1034 "letter-digit-hyphen" ARPANET host name rules
+ domainname hostname; // Host Name, e.g. "Foo.local."
+ UTF8str255 HIHardware;
+ UTF8str255 HISoftware;
+ AuthRecord *ResourceRecords;
+ AuthRecord *DuplicateRecords; // Records currently 'on hold' because they are duplicates of existing records
+ AuthRecord *LocalOnlyRecords; // Local records registered with InterfaceID set to ~0 ("local only")
+ AuthRecord *NewLocalOnlyRecords; // Fresh local-only records not yet delivered to local-only questions
+ mDNSBool DiscardLocalOnlyRecords;// Set when we have "remove" events we need to deliver to local-only questions
+ AuthRecord *CurrentRecord; // Next AuthRecord about to be examined
+ NetworkInterfaceInfo *HostInterfaces;
+ mDNSs32 ProbeFailTime;
+ mDNSs32 NumFailedProbes;
+ mDNSs32 SuppressProbes;
+ };
+
+// ***************************************************************************
+#if 0
+#pragma mark - Useful Static Constants
+#endif
+
+extern const mDNSIPPort zeroIPPort;
+extern const mDNSv4Addr zeroIPAddr;
+extern const mDNSv6Addr zerov6Addr;
+extern const mDNSv4Addr onesIPv4Addr;
+extern const mDNSv6Addr onesIPv6Addr;
+extern const mDNSInterfaceID mDNSInterface_Any;
+
+extern const mDNSIPPort UnicastDNSPort;
+extern const mDNSIPPort MulticastDNSPort;
+extern const mDNSv4Addr AllDNSAdminGroup;
+extern const mDNSv4Addr AllDNSLinkGroup;
+extern const mDNSv6Addr AllDNSLinkGroupv6;
+extern const mDNSAddr AllDNSLinkGroup_v4;
+extern const mDNSAddr AllDNSLinkGroup_v6;
+
+// ***************************************************************************
+#if 0
+#pragma mark - Main Client Functions
+#endif
+
+// Every client should call mDNS_Init, passing in storage for the mDNS object, mDNS_PlatformSupport object, and rrcache.
+// The rrcachesize parameter is the size of (i.e. number of entries in) the rrcache array passed in.
+// Most clients use mDNS_Init_AdvertiseLocalAddresses. This causes mDNSCore to automatically
+// create the correct address records for all the hosts interfaces. If you plan to advertise
+// services being offered by the local machine, this is almost always what you want.
+// There are two cases where you might use mDNS_Init_DontAdvertiseLocalAddresses:
+// 1. A client-only device, that browses for services but doesn't advertise any of its own.
+// 2. A proxy-registration service, that advertises services being offered by other machines, and takes
+// the appropriate steps to manually create the correct address records for those other machines.
+// In principle, a proxy-like registration service could manually create address records for its own machine too,
+// but this would be pointless extra effort when using mDNS_Init_AdvertiseLocalAddresses does that for you.
+//
+// When mDNS has finished setting up the client's callback is called
+// A client can also spin and poll the mDNSPlatformStatus field to see when it changes from mStatus_Waiting to mStatus_NoError
+//
+// Call mDNS_Close to tidy up before exiting
+//
+// Call mDNS_Register with a completed AuthRecord object to register a resource record
+// If the resource record type is kDNSRecordTypeUnique (or kDNSknownunique) then if a conflicting resource record is discovered,
+// the resource record's mDNSRecordCallback will be called with error code mStatus_NameConflict. The callback should deregister
+// the record, and may then try registering the record again after picking a new name (e.g. by automatically appending a number).
+//
+// Call mDNS_StartQuery to initiate a query. mDNS will proceed to issue Multicast DNS query packets, and any time a response
+// is received containing a record which matches the question, the DNSQuestion's mDNSAnswerCallback function will be called
+// Call mDNS_StopQuery when no more answers are required
+//
+// Care should be taken on multi-threaded or interrupt-driven environments.
+// The main mDNS routines call mDNSPlatformLock() on entry and mDNSPlatformUnlock() on exit;
+// each platform layer needs to implement these appropriately for its respective platform.
+// For example, if the support code on a particular platform implements timer callbacks at interrupt time, then
+// mDNSPlatformLock/Unlock need to disable interrupts or do similar concurrency control to ensure that the mDNS
+// code is not entered by an interrupt-time timer callback while in the middle of processing a client call.
+
+extern mStatus mDNS_Init (mDNS *const m, mDNS_PlatformSupport *const p,
+ CacheRecord *rrcachestorage, mDNSu32 rrcachesize,
+ mDNSBool AdvertiseLocalAddresses,
+ mDNSCallback *Callback, void *Context);
+// See notes above on use of NoCache/ZeroCacheSize
+#define mDNS_Init_NoCache mDNSNULL
+#define mDNS_Init_ZeroCacheSize 0
+// See notes above on use of Advertise/DontAdvertiseLocalAddresses
+#define mDNS_Init_AdvertiseLocalAddresses mDNStrue
+#define mDNS_Init_DontAdvertiseLocalAddresses mDNSfalse
+#define mDNS_Init_NoInitCallback mDNSNULL
+#define mDNS_Init_NoInitCallbackContext mDNSNULL
+
+extern void mDNS_GrowCache (mDNS *const m, CacheRecord *storage, mDNSu32 numrecords);
+extern void mDNS_Close (mDNS *const m);
+extern mDNSs32 mDNS_Execute (mDNS *const m);
+
+extern mStatus mDNS_Register (mDNS *const m, AuthRecord *const rr);
+extern mStatus mDNS_Update (mDNS *const m, AuthRecord *const rr, mDNSu32 newttl,
+ const mDNSu16 newrdlength,
+ RData *const newrdata, mDNSRecordUpdateCallback *Callback);
+extern mStatus mDNS_Deregister(mDNS *const m, AuthRecord *const rr);
+
+extern mStatus mDNS_StartQuery(mDNS *const m, DNSQuestion *const question);
+extern mStatus mDNS_StopQuery (mDNS *const m, DNSQuestion *const question);
+extern mStatus mDNS_Reconfirm (mDNS *const m, CacheRecord *const cacherr);
+extern mStatus mDNS_ReconfirmByValue(mDNS *const m, ResourceRecord *const rr);
+
+// ***************************************************************************
+#if 0
+#pragma mark - Platform support functions that are accessible to the client layer too
+#endif
+
+extern mDNSs32 mDNSPlatformOneSecond;
+extern mDNSs32 mDNSPlatformTimeNow(void);
+
+// ***************************************************************************
+#if 0
+#pragma mark - General utility and helper functions
+#endif
+
+// mDNS_RegisterService is a single call to register the set of resource records associated with a given named service.
+//
+// mDNS_StartResolveService is single call which is equivalent to multiple calls to mDNS_StartQuery,
+// to find the IP address, port number, and demultiplexing information for a given named service.
+// As with mDNS_StartQuery, it executes asynchronously, and calls the ServiceInfoQueryCallback when the answer is
+// found. After the service is resolved, the client should call mDNS_StopResolveService to complete the transaction.
+// The client can also call mDNS_StopResolveService at any time to abort the transaction.
+//
+// mDNS_GetBrowseDomains is a special case of the mDNS_StartQuery call, where the resulting answers
+// are a list of PTR records indicating (in the rdata) domains that are recommended for browsing.
+// After getting the list of domains to browse, call mDNS_StopQuery to end the search.
+// mDNS_GetDefaultBrowseDomain returns the name of the domain that should be highlighted by default.
+//
+// mDNS_GetRegistrationDomains and mDNS_GetDefaultRegistrationDomain are the equivalent calls to get the list
+// of one or more domains that should be offered to the user as choices for where they may register their service,
+// and the default domain in which to register in the case where the user has made no selection.
+
+extern void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mDNSInterfaceID InterfaceID,
+ mDNSu16 rrtype, mDNSu32 ttl, mDNSu8 RecordType, mDNSRecordCallback Callback, void *Context);
+
+extern mStatus mDNS_RegisterService (mDNS *const m, ServiceRecordSet *sr,
+ const domainlabel *const name, const domainname *const type, const domainname *const domain,
+ const domainname *const host, mDNSIPPort port, const mDNSu8 txtinfo[], mDNSu16 txtlen,
+ AuthRecord *SubTypes, mDNSu32 NumSubTypes,
+ const mDNSInterfaceID InterfaceID, mDNSServiceCallback Callback, void *Context);
+extern mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra, RData *rdata, mDNSu32 ttl);
+extern mStatus mDNS_RemoveRecordFromService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra);
+extern mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordSet *const sr, const domainlabel *newname);
+extern mStatus mDNS_DeregisterService(mDNS *const m, ServiceRecordSet *sr);
+
+extern mStatus mDNS_RegisterNoSuchService(mDNS *const m, AuthRecord *const rr,
+ const domainlabel *const name, const domainname *const type, const domainname *const domain,
+ const domainname *const host,
+ const mDNSInterfaceID InterfaceID, mDNSRecordCallback Callback, void *Context);
+#define mDNS_DeregisterNoSuchService mDNS_Deregister
+
+extern mStatus mDNS_StartBrowse(mDNS *const m, DNSQuestion *const question,
+ const domainname *const srv, const domainname *const domain,
+ const mDNSInterfaceID InterfaceID, mDNSQuestionCallback *Callback, void *Context);
+#define mDNS_StopBrowse mDNS_StopQuery
+
+extern mStatus mDNS_StartResolveService(mDNS *const m, ServiceInfoQuery *query, ServiceInfo *info, mDNSServiceInfoQueryCallback *Callback, void *Context);
+extern void mDNS_StopResolveService (mDNS *const m, ServiceInfoQuery *query);
+
+typedef enum
+ {
+ mDNS_DomainTypeBrowse = 0,
+ mDNS_DomainTypeBrowseDefault = 1,
+ mDNS_DomainTypeRegistration = 2,
+ mDNS_DomainTypeRegistrationDefault = 3
+ } mDNS_DomainType;
+
+extern mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, mDNS_DomainType DomainType, const mDNSInterfaceID InterfaceID, mDNSQuestionCallback *Callback, void *Context);
+// In the Panther mDNSResponder we don't do unicast queries yet, so there's no point trying to do domain enumeration
+// mDNS_GetDomains() and mDNS_StopGetDomains() are set to be no-ops so that clients don't try to do browse/register operations that will fail
+//#define mDNS_StopGetDomains mDNS_StopQuery
+#define mDNS_StopGetDomains(m,q) ((void)(m),(void)(q))
+extern mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr, mDNS_DomainType DomainType, const mDNSInterfaceID InterfaceID, char *domname);
+#define mDNS_StopAdvertiseDomains mDNS_Deregister
+
+// ***************************************************************************
+#if 0
+#pragma mark - DNS name utility functions
+#endif
+
+// In order to expose the full capabilities of the DNS protocol (which allows any arbitrary eight-bit values
+// in domain name labels, including unlikely characters like ascii nulls and even dots) all the mDNS APIs
+// work with DNS's native length-prefixed strings. For convenience in C, the following utility functions
+// are provided for converting between C's null-terminated strings and DNS's length-prefixed strings.
+
+// Assignment
+// A simple C structure assignment of a domainname can cause a protection fault by accessing unmapped memory,
+// because that object is defined to be 256 bytes long, but not all domainname objects are truly the full size.
+// This macro uses mDNSPlatformMemCopy() to make sure it only touches the actual bytes that are valid.
+#define AssignDomainName(DST, SRC) mDNSPlatformMemCopy((SRC).c, (DST).c, DomainNameLength(&(SRC)))
+
+// Comparison functions
+extern mDNSBool SameDomainLabel(const mDNSu8 *a, const mDNSu8 *b);
+extern mDNSBool SameDomainName(const domainname *const d1, const domainname *const d2);
+
+// Get total length of domain name, in native DNS format, including terminal root label
+// (e.g. length of "com." is 5 (length byte, three data bytes, final zero)
+extern mDNSu16 DomainNameLength(const domainname *const name);
+
+// Append functions to append one or more labels to an existing native format domain name:
+// AppendLiteralLabelString adds a single label from a literal C string, with no escape character interpretation.
+// AppendDNSNameString adds zero or more labels from a C string using conventional DNS dots-and-escaping interpretation
+// AppendDomainLabel adds a single label from a native format domainlabel
+// AppendDomainName adds zero or more labels from a native format domainname
+extern mDNSu8 *AppendLiteralLabelString(domainname *const name, const char *cstr);
+extern mDNSu8 *AppendDNSNameString (domainname *const name, const char *cstr);
+extern mDNSu8 *AppendDomainLabel (domainname *const name, const domainlabel *const label);
+extern mDNSu8 *AppendDomainName (domainname *const name, const domainname *const append);
+
+// Convert from null-terminated string to native DNS format:
+// The DomainLabel form makes a single label from a literal C string, with no escape character interpretation.
+// The DomainName form makes native format domain name from a C string using conventional DNS interpretation:
+// dots separate labels, and within each label, '\.' represents a literal dot, '\\' represents a literal
+// backslash and backslash with three decimal digits (e.g. \000) represents an arbitrary byte value.
+extern mDNSBool MakeDomainLabelFromLiteralString(domainlabel *const label, const char *cstr);
+extern mDNSu8 *MakeDomainNameFromDNSNameString (domainname *const name, const char *cstr);
+
+// Convert native format domainlabel or domainname back to C string format
+// IMPORTANT:
+// When using ConvertDomainLabelToCString, the target buffer must be MAX_ESCAPED_DOMAIN_LABEL (254) bytes long
+// to guarantee there will be no buffer overrun. It is only safe to use a buffer shorter than this in rare cases
+// where the label is known to be constrained somehow (for example, if the label is known to be either "_tcp" or "_udp").
+// Similarly, when using ConvertDomainNameToCString, the target buffer must be MAX_ESCAPED_DOMAIN_NAME (1005) bytes long.
+// See definitions of MAX_ESCAPED_DOMAIN_LABEL and MAX_ESCAPED_DOMAIN_NAME for more detailed explanation.
+extern char *ConvertDomainLabelToCString_withescape(const domainlabel *const name, char *cstr, char esc);
+#define ConvertDomainLabelToCString_unescaped(D,C) ConvertDomainLabelToCString_withescape((D), (C), 0)
+#define ConvertDomainLabelToCString(D,C) ConvertDomainLabelToCString_withescape((D), (C), '\\')
+extern char *ConvertDomainNameToCString_withescape(const domainname *const name, char *cstr, char esc);
+#define ConvertDomainNameToCString_unescaped(D,C) ConvertDomainNameToCString_withescape((D), (C), 0)
+#define ConvertDomainNameToCString(D,C) ConvertDomainNameToCString_withescape((D), (C), '\\')
+
+extern void ConvertUTF8PstringToRFC1034HostLabel(const mDNSu8 UTF8Name[], domainlabel *const hostlabel);
+
+extern mDNSu8 *ConstructServiceName(domainname *const fqdn, const domainlabel *name, const domainname *type, const domainname *const domain);
+extern mDNSBool DeconstructServiceName(const domainname *const fqdn, domainlabel *const name, domainname *const type, domainname *const domain);
+
+// Note: Some old functions have been replaced by more sensibly-named versions.
+// You can uncomment the hash-defines below if you don't want to have to change your source code right away.
+// When updating your code, note that (unlike the old versions) *all* the new routines take the target object
+// as their first parameter.
+//#define ConvertCStringToDomainName(SRC,DST) MakeDomainNameFromDNSNameString((DST),(SRC))
+//#define ConvertCStringToDomainLabel(SRC,DST) MakeDomainLabelFromLiteralString((DST),(SRC))
+//#define AppendStringLabelToName(DST,SRC) AppendLiteralLabelString((DST),(SRC))
+//#define AppendStringNameToName(DST,SRC) AppendDNSNameString((DST),(SRC))
+//#define AppendDomainLabelToName(DST,SRC) AppendDomainLabel((DST),(SRC))
+//#define AppendDomainNameToName(DST,SRC) AppendDomainName((DST),(SRC))
+
+// ***************************************************************************
+#if 0
+#pragma mark - Other utility functions
+#endif
+
+extern mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, va_list arg);
+extern mDNSu32 mDNS_snprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, ...) IS_A_PRINTF_STYLE_FUNCTION(3,4);
+extern char *DNSTypeName(mDNSu16 rrtype);
+extern char *GetRRDisplayString_rdb(mDNS *const m, const ResourceRecord *rr, RDataBody *rd);
+#define GetRRDisplayString(m, rr) GetRRDisplayString_rdb((m), &(rr)->resrec, &(rr)->resrec.rdata->u)
+extern mDNSBool mDNSSameAddress(const mDNSAddr *ip1, const mDNSAddr *ip2);
+extern void IncrementLabelSuffix(domainlabel *name, mDNSBool RichText);
+
+// ***************************************************************************
+#if 0
+#pragma mark - PlatformSupport interface
+#endif
+
+// This section defines the interface to the Platform Support layer.
+// Normal client code should not use any of types defined here, or directly call any of the functions defined here.
+// The definitions are placed here because sometimes clients do use these calls indirectly, via other supported client operations.
+// For example, AssignDomainName is a macro defined using mDNSPlatformMemCopy()
+
+typedef packedstruct
+ {
+ mDNSOpaque16 id;
+ mDNSOpaque16 flags;
+ mDNSu16 numQuestions;
+ mDNSu16 numAnswers;
+ mDNSu16 numAuthorities;
+ mDNSu16 numAdditionals;
+ } DNSMessageHeader;
+
+// We can send and receive packets up to 9000 bytes (Ethernet Jumbo Frame size, if that ever becomes widely used)
+// However, in the normal case we try to limit packets to 1500 bytes so that we don't get IP fragmentation on standard Ethernet
+// 40 (IPv6 header) + 8 (UDP header) + 12 (DNS message header) + 1440 (DNS message body) = 1500 total
+#define AbsoluteMaxDNSMessageData 8940
+#define NormalMaxDNSMessageData 1440
+typedef packedstruct
+ {
+ DNSMessageHeader h; // Note: Size 12 bytes
+ mDNSu8 data[AbsoluteMaxDNSMessageData]; // 40 (IPv6) + 8 (UDP) + 12 (DNS header) + 8940 (data) = 9000
+ } DNSMessage;
+
+// Every platform support module must provide the following functions.
+// mDNSPlatformInit() typically opens a communication endpoint, and starts listening for mDNS packets.
+// When Setup is complete, the platform support layer calls mDNSCoreInitComplete().
+// mDNSPlatformSendUDP() sends one UDP packet
+// When a packet is received, the PlatformSupport code calls mDNSCoreReceive()
+// mDNSPlatformClose() tidies up on exit
+// Note: mDNSPlatformMemAllocate/mDNSPlatformMemFree are only required for handling oversized resource records.
+// If your target platform has a well-defined specialized application, and you know that all the records it uses
+// are InlineCacheRDSize or less, then you can just make a simple mDNSPlatformMemAllocate() stub that always returns
+// NULL. InlineCacheRDSize is a compile-time constant, which is set by default to 64. If you need to handle records
+// a little larger than this and you don't want to have to implement run-time allocation and freeing, then you
+// can raise the value of this constant to a suitable value (at the expense of increased memory usage).
+extern mStatus mDNSPlatformInit (mDNS *const m);
+extern void mDNSPlatformClose (mDNS *const m);
+extern mStatus mDNSPlatformSendUDP(const mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end,
+ mDNSInterfaceID InterfaceID, mDNSIPPort srcport, const mDNSAddr *dst, mDNSIPPort dstport);
+
+extern void mDNSPlatformLock (const mDNS *const m);
+extern void mDNSPlatformUnlock (const mDNS *const m);
+
+extern void mDNSPlatformStrCopy (const void *src, void *dst);
+extern mDNSu32 mDNSPlatformStrLen (const void *src);
+extern void mDNSPlatformMemCopy (const void *src, void *dst, mDNSu32 len);
+extern mDNSBool mDNSPlatformMemSame (const void *src, const void *dst, mDNSu32 len);
+extern void mDNSPlatformMemZero ( void *dst, mDNSu32 len);
+extern void * mDNSPlatformMemAllocate (mDNSu32 len);
+extern void mDNSPlatformMemFree (void *mem);
+extern mStatus mDNSPlatformTimeInit (mDNSs32 *timenow);
+
+// The core mDNS code provides these functions, for the platform support code to call at appropriate times
+//
+// mDNS_GenerateFQDN() is called once on startup (typically from mDNSPlatformInit())
+// and then again on each subsequent change of the dot-local host name.
+//
+// mDNS_RegisterInterface() is used by the platform support layer to inform mDNSCore of what
+// physical and/or logical interfaces are available for sending and receiving packets.
+// Typically it is called on startup for each available interface, but register/deregister may be
+// called again later, on multiple occasions, to inform the core of interface configuration changes.
+// If set->Advertise is set non-zero, then mDNS_RegisterInterface() also registers the standard
+// resource records that should be associated with every publicised IP address/interface:
+// -- Name-to-address records (A/AAAA)
+// -- Address-to-name records (PTR)
+// -- Host information (HINFO)
+//
+// mDNSCoreInitComplete() is called when the platform support layer is finished.
+// Typically this is at the end of mDNSPlatformInit(), but may be later
+// (on platforms like OT that allow asynchronous initialization of the networking stack).
+//
+// mDNSCoreReceive() is called when a UDP packet is received
+//
+// mDNSCoreMachineSleep() is called when the machine sleeps or wakes
+// (This refers to heavyweight laptop-style sleep/wake that disables network access,
+// not lightweight second-by-second CPU power management modes.)
+
+extern void mDNS_GenerateFQDN(mDNS *const m);
+extern mStatus mDNS_RegisterInterface (mDNS *const m, NetworkInterfaceInfo *set);
+extern void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set);
+extern void mDNSCoreInitComplete(mDNS *const m, mStatus result);
+extern void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
+ const mDNSAddr *const srcaddr, const mDNSIPPort srcport,
+ const mDNSAddr *const dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, mDNSu8 ttl);
+extern void mDNSCoreMachineSleep(mDNS *const m, mDNSBool wake);
+
+// ***************************************************************************
+#if 0
+#pragma mark - Compile-Time assertion checks
+#endif
+
+// Some C compiler cleverness. We can make the compiler check certain things for
+// us, and report compile-time errors if anything is wrong. The usual way to do
+// this would be to use a run-time "if" statement, but then you don't find out
+// what's wrong until you run the software. This way, if the assertion condition
+// is false, the array size is negative, and the complier complains immediately.
+
+struct mDNS_CompileTimeAssertionChecks
+ {
+ // Check that the compiler generated our on-the-wire packet format structure definitions
+ // properly packed, without adding padding bytes to align fields on 32-bit or 64-bit boundaries.
+ char assert0[(sizeof(rdataSRV) == 262 ) ? 1 : -1];
+ char assert1[(sizeof(DNSMessageHeader) == 12 ) ? 1 : -1];
+ char assert2[(sizeof(DNSMessage) == 12+AbsoluteMaxDNSMessageData) ? 1 : -1];
+ char assert3[(sizeof(mDNSs8) == 1 ) ? 1 : -1];
+ char assert4[(sizeof(mDNSu8) == 1 ) ? 1 : -1];
+ char assert5[(sizeof(mDNSs16) == 2 ) ? 1 : -1];
+ char assert6[(sizeof(mDNSu16) == 2 ) ? 1 : -1];
+ char assert7[(sizeof(mDNSs32) == 4 ) ? 1 : -1];
+ char assert8[(sizeof(mDNSu32) == 4 ) ? 1 : -1];
+ char assert9[(sizeof(mDNSOpaque16) == 2 ) ? 1 : -1];
+ char assertA[(sizeof(mDNSOpaque32) == 4 ) ? 1 : -1];
+ char assertB[(sizeof(mDNSOpaque128) == 16 ) ? 1 : -1];
+ };
+
+// ***************************************************************************
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif