mDNSClientAPI.h   [plain text]


#pragma once

#include "mDNSDebug.h"

#ifdef	__cplusplus
	extern "C" {
#endif

// ***************************************************************************
// Function scope indicators

// If you see "mDNSlocal" before a function name, it means the function is not callable outside this file
#define mDNSlocal static
// If you see "mDNSexport" before a symbol, it means the symbol is exported for use by clients
#define mDNSexport

// ***************************************************************************
#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]
	kDNSQClass_ANY        = 255,	// Not a DNS class, but a DNS query class, meaning "all classes"
	kDNSQClass_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
	} 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_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 unsigned char  mDNSBool;
typedef   signed char  mDNSs8;
typedef unsigned char  mDNSu8;
typedef   signed short mDNSs16;
typedef unsigned short mDNSu16;
typedef   signed long  mDNSs32;
typedef unsigned long  mDNSu32;

// 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, but don't forget -- just because it is in a register doesn't mean it is an
// integer. Operations like add, multiply, increment, decrement, etc., are undefined for opaque identifiers.
typedef union { mDNSu8 b[2]; mDNSu16 NotAnInteger; } mDNSOpaque16;
typedef union { mDNSu8 b[4]; mDNSu32 NotAnInteger; } mDNSOpaque32;

typedef mDNSOpaque16 mDNSIPPort;		// An IP port is a two-byte opaque identifier (not an integer)
typedef mDNSOpaque32 mDNSIPAddr;		// An IP address is a four-byte opaque identifier (not an integer)

enum { mDNSfalse = 0, mDNStrue = 1 };

#define mDNSNULL 0L

enum
	{
	mStatus_Waiting           = 1,
	mStatus_NoError           = 0,

	// mDNS Error codes are in the range FFFE FF00 (-65792) to FFFE FFFF (-65537)
	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,
	
	mStatus_MemFree           = -65792		// 0xFFFE FF00
	};

typedef mDNSs32 mStatus;

#define MAX_DOMAIN_LABEL 63
typedef struct { mDNSu8 c[ 64]; } domainlabel;		// One label: length byte and up to 63 characters
#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

// ***************************************************************************
#if 0
#pragma mark - Resource Record structures
#endif

// Shared Resource Records do not have to be unique
// -- Shared Resource Records are used for NIAS service PTRs
// -- It is okay for several hosts to have RRs with the same name but different RDATA
// -- We use a random delay on replies to reduce collisions when all the hosts reply 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

// 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
// -- Replies may be sent immediately, because only one host should be replying 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).

enum
	{
	kDNSRecordTypeUnregistered     = 0x00,	// Not currently in any list
	kDNSRecordTypeDeregistering    = 0x01,	// Shared record about to announce its departure and leave the list

	kDNSRecordTypeUnique           = 0x08,	// Will become a kDNSRecordTypeVerified when probing is complete

	kDNSRecordTypePacketAnswer     = 0x10,	// Received in the Answer Section of a DNS Response
	kDNSRecordTypePacketAdditional = 0x11,	// Received in the Additional Section of a DNS Response
	kDNSRecordTypePacketUniqueAns  = 0x18,	// Received in the Answer Section of a DNS Response with kDNSQClass_CacheFlushBit set
	kDNSRecordTypePacketUniqueAdd  = 0x19,	// Received in the Additional Section of a DNS Response with kDNSQClass_CacheFlushBit set

	kDNSRecordTypeShared           = 0x20,	// Shared means record name does not have to be unique -- so use random delay on replies
	kDNSRecordTypeVerified         = 0x28,	// Unique means mDNS should check that name is unique (and then send immediate replies)
	kDNSRecordTypeKnownUnique      = 0x29,	// Known Unique means mDNS can assume name is unique without checking
	
	kDNSRecordTypeUniqueMask       = 0x08,	// Test for records that are supposed to not be shared with other hosts
	kDNSRecordTypeRegisteredMask   = 0xF8,	// Test for records that have not had mDNS_Deregister called on them yet
	kDNSRecordTypeActiveMask       = 0xF0	// Test for all records that have finished their probing and are now active
	};

enum
	{
	kDNSSendPriorityNone       = 0,		// Don't need to send this record right now
	kDNSSendPriorityAdditional = 1,		// Send this record as an additional, if we have space in the packet
	kDNSSendPriorityAnswer     = 2		// Need to send this record as an answer
	};

typedef struct { mDNSu16 priority; mDNSu16 weight; mDNSIPPort port; domainname target; } rdataSRV;

typedef union
	{
	mDNSu8     data[512];	// Generic untyped data (temporarily set 512 for the benefit of iChat)
	mDNSIPAddr ip;			// For 'A' record
	domainname name;		// For PTR and CNAME records
	UTF8str255 txt;			// For TXT record
	rdataSRV   srv;			// For SRV record
	} RDataBody;

typedef struct
	{
	mDNSu16    MaxRDLength;	// Amount of storage allocated for rdata (usually sizeof(RDataBody))
	mDNSu16    RDLength;	// Size of the rdata currently stored here
	RDataBody  u;
	} RData;

typedef struct ResourceRecord_struct ResourceRecord;
typedef struct ResourceRecord_struct *ResourceRecordPtr;

typedef struct mDNS_struct mDNS;
typedef struct mDNS_PlatformSupport_struct mDNS_PlatformSupport;

typedef void mDNSRecordCallback(mDNS *const m, ResourceRecord *const rr, mStatus result);
typedef void mDNSRecordUpdateCallback(mDNS *const m, ResourceRecord *const rr, RData *OldRData);

// Fields labelled "AR:" apply to our authoritative records
// Fields labelled "CR:" apply to cache records
// Fields labelled "--:" apply to both
// (May want to make this a union later, but not now, because using the
// same storage for two different purposes always makes debugging harder.)
struct ResourceRecord_struct
	{
	ResourceRecord     *next;			// --: Next in list
	
	// Field Group 1: Persistent metadata for Authoritative Records
	ResourceRecord     *Additional1;	// AR: Recommended additional record to include in response
	ResourceRecord     *Additional2;	// AR: Another additional
	ResourceRecord     *DependentOn;	// AR: This record depends on another for its uniqueness checking
	ResourceRecord     *RRSet;			// AR: This unique record is part of an RRSet
	mDNSRecordCallback *Callback;		// AR: Callback function to call for state changes
	void               *Context;		// AR: Context parameter for the callback function
	mDNSu8              RecordType;		// --: See enum above
	mDNSu8              HostTarget;		// AR: Set if the target of this record (PTR, CNAME, SRV, etc.) is our host name

	// Field Group 2: Transient state for Authoritative Records
	mDNSu8          Acknowledged;		// AR: Set if we've given the success callback to the client
	mDNSu8          ProbeCount;			// AR: Number of probes remaining before this record is valid (kDNSRecordTypeUnique)
	mDNSu8          AnnounceCount;		// AR: Number of announcements remaining (kDNSRecordTypeShared)
	mDNSu8          IncludeInProbe;		// AR: Set if this RR is being put into a probe right now
	mDNSu8          SendPriority;		// AR: See enum above
	mDNSIPAddr      Requester;			// AR: Used for inter-packet duplicate suppression
										//     If set, give the IP address of the last host that sent a truncated query for this record
										//     If set to all-ones, more than one host sent such a request in the last few milliseconds
	ResourceRecord *NextResponse;		// AR: Link to the next element in the chain of responses to generate
	const mDNSu8   *NR_AnswerTo;		// AR: Set if this record was selected by virtue of being a direct answer to a question
	ResourceRecord *NR_AdditionalTo;	// AR: Set if this record was selected by virtue of being additional to another
	mDNSs32         LastSendTime;		// AR: In platform time units
	mDNSs32         NextSendTime;		// AR: In platform time units
	mDNSs32         NextSendInterval;	// AR: In platform time units
	RData          *NewRData;			// AR: Set if we are updating this record with new rdata
	mDNSRecordUpdateCallback *UpdateCallback;

	// Field Group 3: Transient state for Cache Records
	ResourceRecord *NextDupSuppress;	// CR: Link to the next element in the chain of duplicate suppression answers to send
	mDNSs32         TimeRcvd;			// CR: In platform time units
	mDNSs32         LastUsed;			// CR: In platform time units
	mDNSu32         UseCount;			// CR: Number of times this RR has been used to answer a question
	mDNSu32         UnansweredQueries;	// CR: Number of times we've issued a query for this record without getting an answer
	mDNSBool        Active;				// CR: Set if there is currently a question referencing this answer
	mDNSBool        NewData;			// CR: Set if this is a record we just received

	// Field Group 4: The actual information pertaining to this resource record
	mDNSIPAddr      InterfaceAddr;		// --: Set if this RR is specific to one interface (e.g. a linklocal address)
										// For records received off the wire, InterfaceAddr is *always* set to the receiving interface
										// For our authoritative records, InterfaceAddr is usually zero,
										// except those few records that are interface-specific (e.g. linklocal address records)
	domainname      name;				// --: All the rest are used both in our authoritative records and in cache records
	mDNSu16         rrtype;
	mDNSu16         rrclass;
	mDNSu32         rroriginalttl;		// In seconds.
	mDNSu32         rrremainingttl;		// In seconds. Always set to correct value before calling question callback.
	mDNSu16         rdestimate;			// Upper bound on size of rdata after name compression
	RData           *rdata;				// Pointer to storage for this rdata
	RData           rdatastorage;		// Normally the storage is right here, except for oversized records
	};

typedef struct NetworkInterfaceInfo_struct NetworkInterfaceInfo;

struct NetworkInterfaceInfo_struct
	{
	NetworkInterfaceInfo *next;
	mDNSIPAddr     ip;
	mDNSBool       Advertise;		// Set Advertise to false if you are only searching on this interface
	// Standard ResourceRecords that every Responder host should have (one per active IP address)
	ResourceRecord RR_A1;			// 'A' (address) record for our ".local" name
	ResourceRecord RR_A2;			// 'A' record for our ".local.arpa" name
	ResourceRecord RR_PTR;			// PTR (reverse lookup) record
	};

typedef struct ExtraResourceRecord_struct ExtraResourceRecord;
struct ExtraResourceRecord_struct
	{
	ExtraResourceRecord *next;
	ResourceRecord r;
	// Note: Add any additional fields *before* the ResourceRecord 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 ResourceRecord getting smashed
	};

typedef struct ServiceRecordSet_struct ServiceRecordSet;
typedef void mDNSServiceCallback(mDNS *const m, ServiceRecordSet *const sr, mStatus result);
struct ServiceRecordSet_struct
	{
	mDNSServiceCallback *Callback;
	void                *Context;
	ExtraResourceRecord *Extras;	// Optional list of extra ResourceRecords attached to this service registration
	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
	ResourceRecord       RR_PTR;	// e.g. _printer._tcp.local.      PTR Name._printer._tcp.local.
	ResourceRecord       RR_SRV;	// e.g. Name._printer._tcp.local. SRV 0 0 port target
	ResourceRecord       RR_TXT;	// e.g. Name._printer._tcp.local. TXT PrintQueueName
	// Don't add any fields after ResourceRecord 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

typedef struct DNSQuestion_struct DNSQuestion;
typedef void mDNSQuestionCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer);
struct DNSQuestion_struct
	{
	DNSQuestion          *next;
	mDNSs32               NextQTime;		// In platform time units
	mDNSs32               ThisQInterval;	// In platform time units (zero for questions not in list)
											// ThisQInterval will be non-zero for an active question;
											// Zero for a cancelled or inactive question
	mDNSs32               NextQInterval;
	DNSQuestion          *DuplicateOf;
	mDNSIPAddr            InterfaceAddr;	// Non-zero if you want to issue link-local queries only on a single specific IP interface
	domainname            name;
	mDNSu16               rrtype;
	mDNSu16               rrclass;
	mDNSQuestionCallback *Callback;
	void                 *Context;
	};

typedef struct
	{
	domainname name;
	mDNSIPAddr InterfaceAddr;		// Local (source) IP Interface (needed for scoped addresses such as link-local)
	mDNSIPAddr 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;

typedef struct ServiceInfoQuery_struct ServiceInfoQuery;
typedef void ServiceInfoQueryCallback(mDNS *const m, ServiceInfoQuery *query);
struct ServiceInfoQuery_struct
	{
	DNSQuestion               qSRV;
	DNSQuestion               qTXT;
	DNSQuestion               qADD;
	mDNSu8                    GotSRV;
	mDNSu8                    GotTXT;
	mDNSu8                    GotADD;
	ServiceInfo              *info;
	ServiceInfoQueryCallback *Callback;
	void                     *Context;
	};

// ***************************************************************************
#if 0
#pragma mark - Main mDNS object, used to hold all the mDNS state
#endif

typedef void mDNSCallback(mDNS *const m, mStatus result);

struct mDNS_struct
	{
	mDNS_PlatformSupport *p;		// Pointer to platform-specific data of indeterminite size
	mStatus mDNSPlatformStatus;
	mDNSCallback *Callback;
	void         *Context;

	mDNSu32 mDNS_busy;				// For debugging: To catch and report locking failures

	mDNSu8 lock_rrcache;			// For debugging: Set at times when these lists may not be modified
	mDNSu8 lock_Questions;
	mDNSu8 lock_Records;
	mDNSu8 padding;

	// These fields only required for mDNS Searcher...
	DNSQuestion *ActiveQuestions;	// List of all active questions
	DNSQuestion *NewQuestions;		// Fresh questions not yet answered from cache
	DNSQuestion *CurrentQuestion;	// Next question about to be examined in AnswerLocalQuestions()
	mDNSu32 rrcache_size;
	mDNSu32 rrcache_used;
	mDNSu32 rrcache_report;
	ResourceRecord *rrcache_free;
	ResourceRecord *rrcache;

	// 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  hostname1;			// Primary Host Name "Foo.local."
	domainname  hostname2;			// Secondary Host Name "Foo.local.arpa."
	ResourceRecord *ResourceRecords;
	ResourceRecord *CurrentRecord;	// Next ResourceRecord about to be examined
	NetworkInterfaceInfo *HostInterfaces;
	mDNSs32 SuppressSending;
	mDNSs32 SuppressProbes;
	mDNSBool SleepState;
	mDNSBool NetChanged;
	};

// ***************************************************************************
#if 0
#pragma mark - Useful Static Constants
#endif

extern const ResourceRecord zeroRR;
extern const mDNSIPPort zeroIPPort;
extern const mDNSIPAddr zeroIPAddr;
extern const mDNSIPAddr onesIPAddr;

extern const mDNSIPPort UnicastDNSPort;
extern const mDNSIPPort MulticastDNSPort;
extern const mDNSIPAddr AllDNSLinkGroup;
extern const mDNSIPAddr AllDNSAdminGroup;

// ***************************************************************************
#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.
// When mDNS has finished setting up the initComplete 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 ResourceRecord 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 reply
// 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
//
// The mDNS routines are intentionally not thread-safe -- adding locking operations would add overhead that may not
// be necessary or appropriate on every platform. Instead, code in a pre-emptive environment calling any mDNS routine
// (except mDNS_Init and mDNS_Close) is responsible for doing the necessary synchronization to ensure that mDNS code is
// not re-entered. This includes both client software above mDNS, and the platform support code below. For example, if
// the support code on a particular platform implements timer callbacks at interrupt time, then clients on that platform
// 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,
								ResourceRecord *rrcachestorage, mDNSu32 rrcachesize, mDNSCallback *Callback, void *Context);
extern void    mDNS_Close     (mDNS *const m);
extern mStatus mDNS_Register  (mDNS *const m, ResourceRecord *const rr);
extern mStatus mDNS_Update    (mDNS *const m, ResourceRecord *const rr, mDNSu32 newttl,
								RData *const newrdata, mDNSRecordUpdateCallback *Callback);
extern void    mDNS_Deregister(mDNS *const m, ResourceRecord *const rr);
extern mStatus mDNS_StartQuery(mDNS *const m, DNSQuestion *const question);
extern void    mDNS_StopQuery (mDNS *const m, DNSQuestion *const question);

// ***************************************************************************
#if 0
#pragma mark - General utility and helper functions
#endif

// mDNS_RegisterHostSet is a single call to register the standard resource records associated with every host.
// 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(ResourceRecord *rr, RData *RDataStorage, mDNSIPAddr InterfaceAddr,
               mDNSu16 rrtype, mDNSu32 ttl, mDNSu8 RecordType, mDNSRecordCallback Callback, void *Context);

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 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,
               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 void    mDNS_DeregisterService(mDNS *const m, ServiceRecordSet *sr);

extern mStatus mDNS_StartBrowse(mDNS *const m, DNSQuestion *const question,
				const domainname *const srv, const domainname *const domain,
				const mDNSIPAddr InterfaceAddr, mDNSQuestionCallback *Callback, void *Context);
#define        mDNS_StopBrowse mDNS_StopQuery

extern mStatus mDNS_StartResolveService(mDNS *const m, ServiceInfoQuery *query, ServiceInfo *info, ServiceInfoQueryCallback *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, mDNSu8 DomainType, const mDNSIPAddr InterfaceAddr, mDNSQuestionCallback *Callback, void *Context);
#define        mDNS_StopGetDomains mDNS_StopQuery
extern mStatus mDNS_AdvertiseDomains(mDNS *const m, ResourceRecord *rr, mDNSu8 DomainType, const mDNSIPAddr InterfaceAddr, 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.

extern mDNSBool SameDomainLabel(const mDNSu8 *a, const mDNSu8 *b);
extern mDNSBool SameDomainName(const domainname *const d1, const domainname *const d2);

extern mDNSu32 DomainNameLength(const domainname *const name);
extern void AppendDomainLabelToName(domainname *const name, const domainlabel *const label);
extern void AppendStringLabelToName(domainname *const name, const char *cstr);
extern void AppendDomainNameToName(domainname *const name, const domainname *const append);
extern void AppendStringNameToName(domainname *const name, const char *cstr);

extern void   ConvertCStringToDomainLabel(const char *src, domainlabel *label);
extern mDNSu8 *ConvertCStringToDomainName(const char *const cstr, domainname *name);

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 *const name, const domainname *const type, const domainname *const domain);
extern mDNSBool DeconstructServiceName(const domainname *const fqdn, domainlabel *const name, domainname *const type, domainname *const domain);

#ifdef	__cplusplus
	}
#endif