/* -*- Mode: C; tab-width: 4 -*-
 *
 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.

 * 
 * NOTE:
 * 
 * These .Net APIs are a work in progress, currently being discussed and refined.
 * If you plan to build an application based on these APIs, you may wish to
 * statically link this code into your application, or otherwise distribute
 * the DLL so that it installs into the same folder as your application
 * (not into any common system area where it might interfere with other
 * applications using a future completed version of these APIs).
 * If you plan to do this, please be sure to inform us by sending email
 * to bonjour@apple.com to let us know.
 * You may want to discuss what you're doing on the Bonjour mailing
 * list to see if others in similar positions have any suggestions for you:
 * 
 * <http://lists.apple.com/bonjour-dev/>
 * 
 */
    
#pragma once

#include <dns_sd.h>
#include <vcclr.h>
#include <memory>
#include <winsock2.h>

using namespace System;
using namespace System::Net;
using namespace System::Runtime::InteropServices;
using namespace System::Threading;
using namespace System::Collections;


namespace Apple
{
	namespace DNSSD
	{
		public __gc class ServiceRef;

		public __value enum ServiceFlags : int
		{
			MoreComing			=	1,
			/* MoreComing indicates to a callback that at least one more result is
				* queued and will be delivered following immediately after this one.
				* Applications should not update their UI to display browse
				* results when the MoreComing flag is set, because this would
				* result in a great deal of ugly flickering on the screen.
				* Applications should instead wait until until MoreComing is not set,
				* and then update their UI.
				* When MoreComing is not set, that doesn't mean there will be no more
				* answers EVER, just that there are no more answers immediately
				* available right now at this instant. If more answers become available
				* in the future they will be delivered as usual.
				*/

			Add					=	2,
			Default				=	4,
			/* Flags for domain enumeration and browse/query reply callbacks.
				* "Default" applies only to enumeration and is only valid in
				* conjuction with "Add".  An enumeration callback with the "Add"
				* flag NOT set indicates a "Remove", i.e. the domain is no longer
				* valid.
				*/

			NoAutoRename		=	8,
			/* Flag for specifying renaming behavior on name conflict when registering
				* non-shared records. By default, name conflicts are automatically handled
				* by renaming the service.  NoAutoRename overrides this behavior - with this
				* flag set, name conflicts will result in a callback.  The NoAutorename flag
				* is only valid if a name is explicitly specified when registering a service
				* (i.e. the default name is not used.)
				*/

			Shared				=	16,
			Unique				=	32,
			/* Flag for registering individual records on a connected
				* DNSServiceRef.  Shared indicates that there may be multiple records
				* with this name on the network (e.g. PTR records).  Unique indicates that
	the
				* record's name is to be unique on the network (e.g. SRV records).
				*/

			BrowseDomains		=	64,
			RegistrationDomains	=	128,
			/* Flags for specifying domain enumeration type in DNSServiceEnumerateDomain
	s.
				* BrowseDomains enumerates domains recommended for browsing, RegistrationDo
	mains
				* enumerates domains recommended for registration.
				*/
		};


		public __value enum ErrorCode : int
		{
			NoError				=	0,
			Unknown				=	-65537,
			NoSuchName			=	-65538,
			NoMemory			=	-65539,
			BadParam			=	-65540,
			BadReference		=	-65541,
			BadState			=	-65542,
			BadFlags			=	-65543,
			Unsupported			=	-65544,
			AlreadyRegistered	=	-65547,
			NameConflict		=	-65548,
			Invalid				=	-65549,
			Incompatible		=	-65551,
			BadinterfaceIndex	=	-65552

			/*
				* mDNS Error codes are in the range
				* FFFE FF00 (-65792) to FFFE FFFF (-65537)
				*/
		};

		public __gc class DNSServiceException
		:
			public Exception
		{
		public:

			DNSServiceException
				(
				int err
				);

			DNSServiceException
				(	
				String				*	message,
				System::Exception	*	innerException
				);

			int err;
		};


		/*
		* class RecordRef
		*
		* This is a thin MC++ class facade on top of a DNSRecordRef
		*/
		public __gc class RecordRef
		{
		public:

			RecordRef()
			{
				m_impl = new RecordRefImpl;
				m_impl->m_ref = NULL;
			}

			~RecordRef()
			{
				delete m_impl;
			}

			__nogc class RecordRefImpl
			{
			public:

				DNSRecordRef m_ref;
			};

			RecordRefImpl * m_impl;
		};			


		/*
		* class ServiceRef
		*
		* This is a thin MC++ class facade on top of a DNSServiceRef
		*/
		public __gc class ServiceRef : public IDisposable
		{
		public:

			ServiceRef(Object * callback);

			~ServiceRef();

			/*
			* This does an underlying DNSServiceRefDeallocate().  After
			* calling Dispose, the ServiceRef is no longer usable.
			*/
			void
			Dispose();

			/*
			* Internal - Dispatch an EnumerateDomains callback
			*/
			void
			EnumerateDomainsDispatch
				(
				ServiceFlags	flags,
				int				interfaceIndex,
				ErrorCode		errorCode,
				String		*	replyDomain
				);

			/*
			* Internal - Dispatch a Register callback
			*/
			void
			RegisterDispatch
				(
				ServiceFlags	flags,
				ErrorCode		errorCode,
 				String		*	name,
				String		*	regtype,
				String		*	domain
				);

			/*
			* Internal - Dispatch a Browse callback
			*/
			void
			BrowseDispatch
				(
				ServiceFlags	flags,
				int				interfaceIndex,
				ErrorCode		errorCode,
				String		*	serviceName,
				String		*	regtype,
				String		*	replyDomain
				);

			/*
			* Internal - Dispatch a Resolve callback
			*/
			void
			ResolveDispatch
				(
				ServiceFlags	flags,
				int				interfaceIndex,
				ErrorCode		errorCode,
				String		*	fullname,
				String		*	hosttarget,
				int				port,
				Byte			txtRecord[]
				);
			
			/*
			* Internal - Dispatch a RegisterRecord callback
			*/
			void
			RegisterRecordDispatch
				(
				ServiceFlags	flags,
				ErrorCode		errorCode,
				RecordRef	*	record
				);

			/*
			* Internal - Dispatch a QueryRecord callback
			*/
			void
			QueryRecordDispatch
				(
				ServiceFlags	flags,
				int				interfaceIndex,
				ErrorCode		errorCode,
				String		*	fullname,
				int				rrtype,
				int				rrclass,
				Byte			rdata[],
				int				ttl
				);

			/*
			* Internal - A non managed class to wrap a DNSServiceRef
			*/
			__nogc class ServiceRefImpl
			{
			public:

				ServiceRefImpl
					(
					ServiceRef * outer
					);

				~ServiceRefImpl();

				/*
				* Sets up events for threaded operation
				*/
				void
				SetupEvents();

				/*
				* Main processing thread
				*/
				void
				ProcessingThread();

				/*
				* Calls DNSServiceRefDeallocate()
				*/
				void
				Dispose();

				/*
				* Called from dnssd.dll
				*/
				static void DNSSD_API
				EnumerateDomainsCallback
					(
					DNSServiceRef			sdRef,
					DNSServiceFlags			flags,
					uint32_t				interfaceIndex,
					DNSServiceErrorType		errorCode,
					const char			*	replyDomain,
					void				*	context
					);

				static void DNSSD_API
				RegisterCallback
					(
					DNSServiceRef			ref,
					DNSServiceFlags			flags,
					DNSServiceErrorType		errorCode,
 					const char			*	name,
					const char			*	regtype,
					const char			*	domain,
					void				*	context
					);

				static void DNSSD_API
				BrowseCallback
					(
					DNSServiceRef			sdRef,
   					DNSServiceFlags			flags,
					uint32_t				interfaceIndex,
					DNSServiceErrorType		errorCode,
					const char			*	serviceName,
					const char			*	regtype,
					const char			*	replyDomain,
					void				*	context
					);

				static void DNSSD_API
				ResolveCallback
					(
					DNSServiceRef			sdRef,
					DNSServiceFlags			flags,
					uint32_t				interfaceIndex,
					DNSServiceErrorType		errorCode,
					const char			*	fullname,
					const char			*	hosttarget,
					uint16_t				notAnIntPort,
					uint16_t				txtLen,
					const char			*	txtRecord,
					void				*	context
					);

				static void DNSSD_API
				RegisterRecordCallback
					( 
					DNSServiceRef		sdRef,
					DNSRecordRef		RecordRef,
					DNSServiceFlags		flags,
					DNSServiceErrorType	errorCode,
					void			*	context
					);

				static void DNSSD_API
				QueryRecordCallback
					(
					DNSServiceRef			DNSServiceRef,
					DNSServiceFlags			flags,
					uint32_t				interfaceIndex,
					DNSServiceErrorType		errorCode,
					const char			*	fullname,
					uint16_t				rrtype,
					uint16_t				rrclass,
					uint16_t				rdlen,
					const void			*	rdata,
					uint32_t				ttl,
					void				*	context
					);

				SOCKET				m_socket;
				HANDLE				m_socketEvent;
				HANDLE				m_stopEvent;
				DWORD				m_threadId;
				bool				m_disposed;
				DNSServiceRef		m_ref;
				gcroot<ServiceRef*> m_outer;
			};

			void
			StartThread();

			void
			ProcessingThread();

			bool				m_bDisposed;
			Object			*	m_callback;
			Thread			*	m_thread;
			ServiceRefImpl	*	m_impl;
		};
			
		/*********************************************************************************************
		*
		*   TXT Record Construction Functions
		*
		*********************************************************************************************/

		/*
		* A typical calling sequence for TXT record construction is something like:
		*
		* DNSService.TextRecord tr = new DNSService.TextRecord(1024);
		* tr.SetValue();
		* tr.SetValue();
		* tr.SetValue();
		* ...
		* DNSServiceRegister( ... tr.GetLength(), tr.GetBytes() ... );
		*/


		/* TextRecord
		*
		* Opaque internal data type.
		* Note: Represents a DNS-SD TXT record.
		*/


		/* TextRecord::TextRecord()
		*
		* Creates a new empty TextRecord .
		*
		*/

		public __gc class TextRecord
		{
		public:

			TextRecord()
			{
				m_impl = new TextRecordImpl();
				TXTRecordCreate(&m_impl->m_ref, 0, NULL);
			}

			~TextRecord()
			{
				TXTRecordDeallocate(&m_impl->m_ref);
				delete m_impl;
			}

			__nogc class TextRecordImpl
			{
			public:

				TXTRecordRef m_ref;
			};

			TextRecordImpl * m_impl;


			/* SetValue()
			*
			* Adds a key (optionally with value) to a TextRecord. If the "key" already
			* exists in the TextRecord, then the current value will be replaced with
			* the new value.
			* Keys may exist in four states with respect to a given TXT record:
			*  - Absent (key does not appear at all)
			*  - Present with no value ("key" appears alone)
			*  - Present with empty value ("key=" appears in TXT record)
			*  - Present with non-empty value ("key=value" appears in TXT record)
			* For more details refer to "Data Syntax for DNS-SD TXT Records" in
			* <http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt>
			*
			* key:             A null-terminated string which only contains printable ASCII
			*                  values (0x20-0x7E), excluding '=' (0x3D). Keys should be
			*                  14 characters or less (not counting the terminating null).
			*
			* value:           Any binary value. For values that represent
			*                  textual data, UTF-8 is STRONGLY recommended.
			*                  For values that represent textual data, valueSize
			*                  should NOT include the terminating null (if any)
			*                  at the end of the string.
			*                  If NULL, then "key" will be added with no value.
			*                  If non-NULL but valueSize is zero, then "key=" will be
			*                  added with empty value.
			*
			* exceptions:      Throws kDNSServiceErr_Invalid if the "key" string contains
			*                  illegal characters.
			*                  Throws kDNSServiceErr_NoMemory if adding this key would
			*                  exceed the available storage.
			*/

			void
			SetValue
				(
				String	*	key,
				Byte		value[]  /* may be NULL */
				);


			/* RemoveValue()
			*
			* Removes a key from a TextRecord.  The "key" must be an
			* ASCII string which exists in the TextRecord.
			*
			* key:             A key name which exists in the TextRecord.
			*
			* exceptions:      Throws kDNSServiceErr_NoSuchKey if the "key" does not
			*                  exist in the TextRecord.
			*
			*/

			void
			RemoveValue
				(
				String	*	key
				);


			/* GetLength()
			*
			* Allows you to determine the length of the raw bytes within a TextRecord.
			*
			* return value :     Returns the size of the raw bytes inside a TextRecord
			*                  which you can pass directly to DNSServiceRegister() or
			*                  to DNSServiceUpdateRecord().
			*                  Returns 0 if the TextRecord is empty.
			*
			*/

			int
			GetLength
				(
				);


			/* GetBytes()
			*
			* Allows you to retrieve a pointer to the raw bytes within a TextRecord.
			*
			* return value:    Returns a pointer to the bytes inside the TextRecord
			*                  which you can pass directly to DNSServiceRegister() or
			*                  to DNSServiceUpdateRecord().
			*
			*/

			Byte
			GetBytes
				(
				) __gc[];


			/*********************************************************************************************
			*
			*   TXT Record Parsing Functions
			*
			*********************************************************************************************/

			/*
			* A typical calling sequence for TXT record parsing is something like:
			*
			* Receive TXT record data in DNSServiceResolve() callback
			* if (TXTRecordContainsKey(txtLen, txtRecord, "key")) then do something
			* val1ptr = DNSService.TextService.GetValue(txtRecord, "key1", &len1);
			* val2ptr = DNSService.TextService.GetValue(txtRecord, "key2", &len2);
			* ...
			* return;
			*
			*/

			/* ContainsKey()
			*
			* Allows you to determine if a given TXT Record contains a specified key.
			*
			* txtRecord:       Pointer to the received TXT Record bytes.
			*
			* key:             A null-terminated ASCII string containing the key name.
			*
			* return value:    Returns 1 if the TXT Record contains the specified key.
			*                  Otherwise, it returns 0.
			*
			*/

			static public bool
			ContainsKey
				(
				Byte		txtRecord[],
				String	*	key
				);


			/* GetValueBytes()
			*
			* Allows you to retrieve the value for a given key from a TXT Record.
			*
			* txtRecord:       Pointer to the received TXT Record bytes.
			*
			* key:             A null-terminated ASCII string containing the key name.
			*
			* return value:    Returns NULL if the key does not exist in this TXT record,
			*                  or exists with no value (to differentiate between
			*                  these two cases use ContainsKey()).
			*                  Returns byte array 
			*                  if the key exists with empty or non-empty value.
			*                  For empty value, length of byte array will be zero.
			*                  For non-empty value, it will be the length of value data.
			*/

			static public Byte
			GetValueBytes
				(
				Byte		txtRecord[],
				String	*	key
				) __gc[];


			/* GetCount()
			*
			* Returns the number of keys stored in the TXT Record.  The count
			* can be used with TXTRecordGetItemAtIndex() to iterate through the keys.
			*
			* txtRecord:       Pointer to the received TXT Record bytes.
			*
			* return value:    Returns the total number of keys in the TXT Record.
			*
			*/

			static public int
			GetCount
				(
				Byte	txtRecord[]
				);


			/* GetItemAtIndex()
			*
			* Allows you to retrieve a key name and value pointer, given an index into
			* a TXT Record.  Legal index values range from zero to TXTRecordGetCount()-1.
			* It's also possible to iterate through keys in a TXT record by simply
			* calling TXTRecordGetItemAtIndex() repeatedly, beginning with index zero
			* and increasing until TXTRecordGetItemAtIndex() returns kDNSServiceErr_Invalid.
			*
			* On return:
			* For keys with no value, *value is set to NULL and *valueLen is zero.
			* For keys with empty value, *value is non-NULL and *valueLen is zero.
			* For keys with non-empty value, *value is non-NULL and *valueLen is non-zero.
			*
			* txtRecord:       Pointer to the received TXT Record bytes.
			*
			* index:           An index into the TXT Record.
			*
			* key:             A string buffer used to store the key name.
			*                  On return, the buffer contains a string
			*                  giving the key name. DNS-SD TXT keys are usually
			*                  14 characters or less. 
			*
			* return value:    Record bytes that holds the value data.
			*
			* exceptions:      Throws kDNSServiceErr_Invalid if index is greater than
			*                  GetCount()-1.
			*/

			static public Byte
			GetItemAtIndex
				(
				Byte				txtRecord[],
				int					index,
				[Out] String	**	key
				) __gc[];
		};


		public __abstract __gc class DNSService
		{
		public:

			/*********************************************************************************************
			*
			* Domain Enumeration
			*
			*********************************************************************************************/

			/* DNSServiceEnumerateDomains()
			*
			* Asynchronously enumerate domains available for browsing and registration.
			* Currently, the only domain returned is "local.", but other domains will be returned in future.
			*
			* The enumeration MUST be cancelled via DNSServiceRefDeallocate() when no more domains
			* are to be found.
			*
			*
			* EnumerateDomainsReply Delegate
			*
			* This Delegate is invoked upon a reply from an EnumerateDomains call.
			*
			* sdRef:           The DNSServiceRef initialized by DNSServiceEnumerateDomains().
			*
			* flags:           Possible values are:
			*                  MoreComing
			*                  Add
			*                  Default
			*
			* interfaceIndex:  Specifies the interface on which the domain exists.  (The index for a given
			*                  interface is determined via the if_nametoindex() family of calls.)
			*
			* errorCode:       Will be NoError (0) on success, otherwise indicates
			*                  the failure that occurred (other parameters are undefined if errorCode is nonzero).
			*
			* replyDomain:     The name of the domain.
			*
			*/

			__delegate void
			EnumerateDomainsReply
				(
				ServiceRef	*	sdRef,
				ServiceFlags	flags,
				int				interfaceIndex,
				ErrorCode		errorCode,
				String		*	replyDomain
				);

			/* DNSServiceEnumerateDomains() Parameters:
			*
			*
			* flags:           Possible values are:
			*                  BrowseDomains to enumerate domains recommended for browsing.
			*                  RegistrationDomains to enumerate domains recommended
			*                  for registration.
			*
			* interfaceIndex:  If non-zero, specifies the interface on which to look for domains.
			*                  (the index for a given interface is determined via the if_nametoindex()
			*                  family of calls.)  Most applications will pass 0 to enumerate domains on
			*                  all interfaces.
			*
			* callback:        The delegate to be called when a domain is found or the call asynchronously
			*                  fails.
			*
			*
			* return value:    Returns initialize ServiceRef on succeses (any subsequent, asynchronous
			*                  errors are delivered to the delegate), otherwise throws an exception indicating
			*                  the error that occurred (the callback is not invoked and the ServiceRef
			*                  is not initialized.)
			*/

			static public ServiceRef*
			EnumerateDomains
				(
				int							flags,
				int							interfaceIndex,
				EnumerateDomainsReply	*	callback
				);

			/*********************************************************************************************
			*
			*  Service Registration
			*
			*********************************************************************************************/

			/* Register a service that is discovered via Browse() and Resolve() calls.
			* 
			* RegisterReply() Callback Parameters:
			*
			* sdRef:           The ServiceRef initialized by Register().
			*
			* flags:           Currently unused, reserved for future use.
			*
			* errorCode:       Will be NoError on success, otherwise will
			*                  indicate the failure that occurred (including name conflicts, if the
			*                  NoAutoRename flag was passed to the
			*                  callout.)  Other parameters are undefined if errorCode is nonzero.
			*
			* name:            The service name registered (if the application did not specify a name in
			*                  DNSServiceRegister(), this indicates what name was automatically chosen).
			*
			* regtype:         The type of service registered, as it was passed to the callout.
			*
			* domain:          The domain on which the service was registered (if the application did not
			*                  specify a domain in Register(), this indicates the default domain
			*                  on which the service was registered).
			*
			*/

			__delegate void
			RegisterReply
				(
				ServiceRef	*	sdRef,
				ServiceFlags	flags,
				ErrorCode		errorCode,
				String		*	name,
				String		*	regtype,
				String		*	domain
				);

			/* Register()  Parameters:
			*
			* flags:           Indicates the renaming behavior on name conflict (most applications
			*                  will pass 0).  See flag definitions above for details.
			*
			* interfaceIndex:  If non-zero, specifies the interface on which to register the service
			*                  (the index for a given interface is determined via the if_nametoindex()
			*                  family of calls.)  Most applications will pass 0 to register on all
			*                  available interfaces.  Pass -1 to register a service only on the local
			*                  machine (service will not be visible to remote hosts.)
			*
			* name:            If non-NULL, specifies the service name to be registered.
			*                  Most applications will not specify a name, in which case the
			*                  computer name is used (this name is communicated to the client via
			*                  the callback).
			*
			* regtype:         The service type followed by the protocol, separated by a dot
			*                  (e.g. "_ftp._tcp").  The transport protocol must be "_tcp" or "_udp".
			*                  New service types should be registered at htp://www.dns-sd.org/ServiceTypes.html.
			*
			* domain:          If non-NULL, specifies the domain on which to advertise the service.
			*                  Most applications will not specify a domain, instead automatically
			*                  registering in the default domain(s).
			*
			* host:            If non-NULL, specifies the SRV target host name.  Most applications
			*                  will not specify a host, instead automatically using the machine's
			*                  default host name(s).  Note that specifying a non-NULL host does NOT
			*                  create an address record for that host - the application is responsible
			*                  for ensuring that the appropriate address record exists, or creating it
			*                  via DNSServiceRegisterRecord().
			*
			* port:            The port, in host byte order, on which the service accepts connections.
			*                  Pass 0 for a "placeholder" service (i.e. a service that will not be discovered
			*                  by browsing, but will cause a name conflict if another client tries to
			*                  register that same name).  Most clients will not use placeholder services.
			*
			* txtRecord:       The txt record rdata.  May be NULL.  Note that a non-NULL txtRecord
			*                  MUST be a properly formatted DNS TXT record, i.e. <length byte> <data>
			*                  <length byte> <data> ...
			*
			* callback:        The delegate to be called when the registration completes or asynchronously
			*                  fails.  The client MAY pass NULL for the callback -  The client will NOT be notified
			*                  of the default values picked on its behalf, and the client will NOT be notified of any
			*                  asynchronous errors (e.g. out of memory errors, etc.) that may prevent the registration
			*                  of the service.  The client may NOT pass the NoAutoRename flag if the callback is NULL.
			*                  The client may still deregister the service at any time via DNSServiceRefDeallocate().
			*
			* return value:    Returns initialize ServiceRef (any subsequent, asynchronous
			*                  errors are delivered to the callback), otherwise throws an exception indicating
			*                  the error that occurred (the callback is never invoked and the DNSServiceRef
			*                  is not initialized.)
			*
			*/
			static public ServiceRef*
			Register
				(
				int					flags,
				int					interfaceIndex,
				String			*	name,
				String			*	regtype,
				String			*	domain,
				String			*	host,
				int					port,
				Byte				txtRecord[],
				RegisterReply	*	callback
				);

			/* AddRecord()
			*
			* Add a record to a registered service.  The name of the record will be the same as the
			* registered service's name.
			* The record can later be updated or deregistered by passing the RecordRef initialized
			* by this function to UpdateRecord() or RemoveRecord().
			*
			*
			* Parameters;
			*
			* sdRef:           A ServiceRef initialized by Register().
			*
			* RecordRef:       A pointer to an uninitialized RecordRef.  Upon succesfull completion of this
			*                  call, this ref may be passed to UpdateRecord() or RemoveRecord().
			*                  If the above ServiceRef is disposed, RecordRef is also
			*                  invalidated and may not be used further.
			*
			* flags:           Currently ignored, reserved for future use.
			*
			* rrtype:          The type of the record (e.g. TXT, SRV, etc), as defined in nameser.h.
			*
			* rdata:           The raw rdata to be contained in the added resource record.
			*
			* ttl:             The time to live of the resource record, in seconds.
			*
			* return value:    Returns initialized RecordRef, otherwise throws
			*                  an exception indicating the error that occurred (the RecordRef is not initialized).
			*/

			static public RecordRef*
			AddRecord
				(
				ServiceRef	*	sref,
				int				flags,
				int				rrtype,
				Byte			rdata[],
				int				ttl
				);

			/* UpdateRecord
			*
			* Update a registered resource record.  The record must either be:
			*   - The primary txt record of a service registered via Register()
			*   - A record added to a registered service via AddRecord()
			*   - An individual record registered by RegisterRecord()
			*
			*
			* Parameters:
			*
			* sdRef:           A ServiceRef that was initialized by Register()
			*                  or CreateConnection().
			*
			* RecordRef:       A RecordRef initialized by AddRecord, or NULL to update the
			*                  service's primary txt record.
			*
			* flags:           Currently ignored, reserved for future use.
			*
			* rdata:           The new rdata to be contained in the updated resource record.
			*
			* ttl:             The time to live of the updated resource record, in seconds.
			*
			* return value:    No return value on success, otherwise throws an exception
			*                  indicating the error that occurred.
			*/
			static public void
			UpdateRecord
				(
				ServiceRef	*	sref,
				RecordRef	*	record,
				int				flags,
				Byte			rdata[],
				int				ttl
				);

			/* RemoveRecord
			*
			* Remove a record previously added to a service record set via AddRecord(), or deregister
			* an record registered individually via RegisterRecord().
			*
			* Parameters:
			*
			* sdRef:           A ServiceRef initialized by Register() (if the
			*                  record being removed was registered via AddRecord()) or by
			*                  CreateConnection() (if the record being removed was registered via
			*                  RegisterRecord()).
			*
			* recordRef:       A RecordRef initialized by a successful call to AddRecord()
			*                  or RegisterRecord().
			*
			* flags:           Currently ignored, reserved for future use.
			*
			* return value:    Nothing on success, otherwise throws an
			*                  exception indicating the error that occurred.
			*/

			static public void
			RemoveRecord
							(
							ServiceRef	*	sref,
							RecordRef	*	record,	
							int				flags
							);

			/*********************************************************************************************
			*
			*  Service Discovery
			*
			*********************************************************************************************/

			/* Browse for instances of a service.
			*
			*
			* BrowseReply() Parameters:
			*
			* sdRef:           The DNSServiceRef initialized by Browse().
			*
			* flags:           Possible values are MoreComing and Add.
			*                  See flag definitions for details.
			*
			* interfaceIndex:  The interface on which the service is advertised.  This index should
			*                  be passed to Resolve() when resolving the service.
			*
			* errorCode:       Will be NoError (0) on success, otherwise will
			*                  indicate the failure that occurred.  Other parameters are undefined if
			*                  the errorCode is nonzero.
			*
			* serviceName:     The service name discovered.
			*
			* regtype:         The service type, as passed in to Browse().
			* 
			* domain:          The domain on which the service was discovered (if the application did not
			*                  specify a domain in Browse(), this indicates the domain on which the
			*                  service was discovered.)
			*
			*/

			__delegate void
			BrowseReply
				(
				ServiceRef	*	sdRef,
				ServiceFlags	flags,
				int				interfaceIndex,
				ErrorCode		errorCode,
				String		*	name,
				String		*	type,
				String		*	domain
				);

			/* DNSServiceBrowse() Parameters:
			*
			* sdRef:           A pointer to an uninitialized ServiceRef.  Call ServiceRef.Dispose()
			*                  to terminate the browse.
			*
			* flags:           Currently ignored, reserved for future use.
			*
			* interfaceIndex:  If non-zero, specifies the interface on which to browse for services
			*                  (the index for a given interface is determined via the if_nametoindex()
			*                  family of calls.)  Most applications will pass 0 to browse on all available
			*                  interfaces.  Pass -1 to only browse for services provided on the local host.
			*
			* regtype:         The service type being browsed for followed by the protocol, separated by a
			*                  dot (e.g. "_ftp._tcp").  The transport protocol must be "_tcp" or "_udp".
			*
			* domain:          If non-NULL, specifies the domain on which to browse for services.
			*                  Most applications will not specify a domain, instead browsing on the
			*                  default domain(s).
			*
			* callback:        The delegate to be called when an instance of the service being browsed for
			*                  is found, or if the call asynchronously fails.
			*
			* return value:    Returns initialized ServiceRef on succeses (any subsequent, asynchronous
			*                  errors are delivered to the callback), otherwise throws an exception indicating
			*                  the error that occurred (the callback is not invoked and the ServiceRef
			*                  is not initialized.)
			*/

			static public ServiceRef*
			Browse
				(
				int				flags,
				int				interfaceIndex,
				String		*	regtype,
				String		*	domain,
				BrowseReply	*	callback
				);

			/* ResolveReply() Parameters:
			*
			* Resolve a service name discovered via Browse() to a target host name, port number, and
			* txt record.
			*
			* Note: Applications should NOT use Resolve() solely for txt record monitoring - use
			* QueryRecord() instead, as it is more efficient for this task.
			*
			* Note: When the desired results have been returned, the client MUST terminate the resolve by calling
			* ServiceRef.Dispose().
			*
			* Note: Resolve() behaves correctly for typical services that have a single SRV record and
			* a single TXT record (the TXT record may be empty.)  To resolve non-standard services with multiple
			* SRV or TXT records, QueryRecord() should be used.
			*
			* ResolveReply Callback Parameters:
			*
			* sdRef:           The DNSServiceRef initialized by Resolve().
			*
			* flags:           Currently unused, reserved for future use.
			*
			* interfaceIndex:  The interface on which the service was resolved.
			*
			* errorCode:       Will be NoError (0) on success, otherwise will
			*                  indicate the failure that occurred.  Other parameters are undefined if
			*                  the errorCode is nonzero.
			*
			* fullname:        The full service domain name, in the form <servicename>.<protocol>.<domain>.
			*                  (Any literal dots (".") are escaped with a backslash ("\."), and literal
			*                  backslashes are escaped with a second backslash ("\\"), e.g. a web server
			*                  named "Dr. Pepper" would have the fullname  "Dr\.\032Pepper._http._tcp.local.").
			*                  This is the appropriate format to pass to standard system DNS APIs such as
			*                  res_query(), or to the special-purpose functions included in this API that
			*                  take fullname parameters.
			*
			* hosttarget:      The target hostname of the machine providing the service.  This name can
			*                  be passed to functions like gethostbyname() to identify the host's IP address.
			*
			* port:            The port, in host byte order, on which connections are accepted for this service.
			*
			* txtRecord:       The service's primary txt record, in standard txt record format.
			*
			*/

			__delegate void
			ResolveReply
				(	
				ServiceRef	*	sdRef,  
				ServiceFlags	flags,
				int				interfaceIndex,
				ErrorCode		errorCode,
				String		*	fullName,
				String		*	hostName,
				int				port,
				Byte			txtRecord[]
				);

			/* Resolve() Parameters
			*
			* flags:           Currently ignored, reserved for future use.
			*
			* interfaceIndex:  The interface on which to resolve the service.  The client should
			*                  pass the interface on which the servicename was discovered, i.e.
			*                  the interfaceIndex passed to the DNSServiceBrowseReply callback,
			*                  or 0 to resolve the named service on all available interfaces.
			*
			* name:            The servicename to be resolved.
			*
			* regtype:         The service type being resolved followed by the protocol, separated by a
			*                  dot (e.g. "_ftp._tcp").  The transport protocol must be "_tcp" or "_udp".
			*
			* domain:          The domain on which the service is registered, i.e. the domain passed
			*                  to the DNSServiceBrowseReply callback.
			*
			* callback:        The delegate to be called when a result is found, or if the call
			*                  asynchronously fails.
			*
			*
			* return value:    Returns initialized ServiceRef on succeses (any subsequent, asynchronous
			*                  errors are delivered to the callback), otherwise throws an exception indicating
			*                  the error that occurred (the callback is never invoked and the DNSServiceRef
			*                  is not initialized.)
			*/

			static public ServiceRef*
			Resolve
				(
				int					flags,
				int					interfaceIndex,
				String			*	name,
				String			*	regtype,
				String			*	domain,
				ResolveReply	*	callback
				);

			/*********************************************************************************************
			*
			*  Special Purpose Calls (most applications will not use these)
			*
			*********************************************************************************************/

			/* CreateConnection/RegisterRecord
			*
			* Register an individual resource record on a connected ServiceRef.
			*
			* Note that name conflicts occurring for records registered via this call must be handled
			* by the client in the callback.
			*
			*
			* RecordReply() parameters:
			*
			* sdRef:           The connected ServiceRef initialized by
			*                  CreateConnection().
			*
			* RecordRef:       The RecordRef initialized by RegisterRecord().  If the above
			*                  ServiceRef.Dispose is called, this RecordRef is
			*                  invalidated, and may not be used further.
			*
			* flags:           Currently unused, reserved for future use.
			*
			* errorCode:       Will be NoError on success, otherwise will
			*                  indicate the failure that occurred (including name conflicts.)
			*                  Other parameters are undefined if errorCode is nonzero.
			*
			*/

			__delegate void
			RegisterRecordReply
				(
				ServiceRef	*	sdRef,
				ServiceFlags	flags,
				ErrorCode		errorCode,
				RecordRef	*	record
				);

			/* CreateConnection()
			*
			* Create a connection to the daemon allowing efficient registration of
			* multiple individual records.
			*
			*
			* Parameters:
			*
			* callback:        The delegate to be called when a result is found, or if the call
			*                  asynchronously fails (e.g. because of a name conflict.)
			*
			* return value:    Returns initialize ServiceRef on success, otherwise throws
			*                  an exception indicating the specific failure that occurred (in which
			*                  case the ServiceRef is not initialized).
			*/

			static public ServiceRef*
			CreateConnection
				(
				RegisterRecordReply * callback
				);


			/* RegisterRecord() Parameters:
			*
			* sdRef:           A ServiceRef initialized by CreateConnection().
			*
			* RecordRef:       A pointer to an uninitialized RecordRef.  Upon succesfull completion of this
			*                  call, this ref may be passed to UpdateRecord() or RemoveRecord().
			*                  (To deregister ALL records registered on a single connected ServiceRef
			*                  and deallocate each of their corresponding RecordRefs, call
			*                  ServiceRef.Dispose()).
			*
			* flags:           Possible values are Shared or Unique
			*                  (see flag type definitions for details).
			*
			* interfaceIndex:  If non-zero, specifies the interface on which to register the record
			*                  (the index for a given interface is determined via the if_nametoindex()
			*                  family of calls.)  Passing 0 causes the record to be registered on all interfaces.
			*                  Passing -1 causes the record to only be visible on the local host.
			*
			* fullname:        The full domain name of the resource record.
			*
			* rrtype:          The numerical type of the resource record (e.g. PTR, SRV, etc), as defined
			*                  in nameser.h.
			*
			* rrclass:         The class of the resource record, as defined in nameser.h (usually 1 for the
			*                  Internet class).
			*
			* rdata:           A pointer to the raw rdata, as it is to appear in the DNS record.
			*
			* ttl:             The time to live of the resource record, in seconds.
			*
			*
			* return value:    Returns initialize RecordRef on succeses (any subsequent, asynchronous
			*                  errors are delivered to the callback), otherwise throws an exception indicating
			*                  the error that occurred (the callback is never invoked and the RecordRef is
			*                  not initialized.)
			*/
			static public RecordRef*
			RegisterRecord
				(
				ServiceRef			*	sdRef,
				ServiceFlags			flags,
				int						interfaceIndex,
				String				*	fullname,
				int						rrtype,
				int						rrclass,
				Byte					rdata[],
				int						ttl
				);


			/* DNSServiceQueryRecord
			*
			* Query for an arbitrary DNS record.
			*
			*
			* QueryRecordReply() Delegate Parameters:
			*
			* sdRef:           The ServiceRef initialized by QueryRecord().
			*
			* flags:           Possible values are MoreComing and
			*                  Add.  The Add flag is NOT set for PTR records
			*                  with a ttl of 0, i.e. "Remove" events.
			*
			* interfaceIndex:  The interface on which the query was resolved (the index for a given
			*                  interface is determined via the if_nametoindex() family of calls).
			*
			* errorCode:       Will be kDNSServiceErr_NoError on success, otherwise will
			*                  indicate the failure that occurred.  Other parameters are undefined if
			*                  errorCode is nonzero.
			*
			* fullname:        The resource record's full domain name.
			*
			* rrtype:          The resource record's type (e.g. PTR, SRV, etc) as defined in nameser.h.
			*
			* rrclass:         The class of the resource record, as defined in nameser.h (usually 1).
			*
			* rdata:           The raw rdata of the resource record.
			*
			* ttl:             The resource record's time to live, in seconds.
			*
			*/

			__delegate void
			QueryRecordReply
				(
				ServiceRef	*	sdRef,
				ServiceFlags	flags,
				int				interfaceIndex,
				ErrorCode		errorCode,	
				String		*	fullName,
				int				rrtype,
				int				rrclass,
				Byte			rdata[],
				int				ttl
				);

			/* QueryRecord() Parameters:
			*
			* flags:           Pass LongLivedQuery to create a "long-lived" unicast
			*                  query in a non-local domain.  Without setting this flag, unicast queries
			*                  will be one-shot - that is, only answers available at the time of the call
			*                  will be returned.  By setting this flag, answers (including Add and Remove
			*                  events) that become available after the initial call is made will generate
			*                  callbacks.  This flag has no effect on link-local multicast queries.
			*
			* interfaceIndex:  If non-zero, specifies the interface on which to issue the query
			*                  (the index for a given interface is determined via the if_nametoindex()
			*                  family of calls.)  Passing 0 causes the name to be queried for on all
			*                  interfaces.  Passing -1 causes the name to be queried for only on the
			*                  local host.
			*
			* fullname:        The full domain name of the resource record to be queried for.
			*
			* rrtype:          The numerical type of the resource record to be queried for (e.g. PTR, SRV, etc)
			*                  as defined in nameser.h.
			*
			* rrclass:         The class of the resource record, as defined in nameser.h
			*                  (usually 1 for the Internet class).
			*
			* callback:        The delegate to be called when a result is found, or if the call
			*                  asynchronously fails.
			*
			*
			* return value:    Returns initialized ServiceRef on succeses (any subsequent, asynchronous
			*                  errors are delivered to the callback), otherwise throws an exception indicating
			*                  the error that occurred (the callback is never invoked and the ServiceRef
			*                  is not initialized.)
			*/

			static public ServiceRef*
			QueryRecord
				(
				ServiceFlags			flags,
				int						interfaceIndex,
				String				*	fullname,
				int						rrtype,
				int						rrclass,
				QueryRecordReply	*	callback
				);

			/* ReconfirmRecord
			*
			* Instruct the daemon to verify the validity of a resource record that appears to
			* be out of date (e.g. because tcp connection to a service's target failed.)
			* Causes the record to be flushed from the daemon's cache (as well as all other
			* daemons' caches on the network) if the record is determined to be invalid.
			*
			* Parameters:
			*
			* flags:           Currently unused, reserved for future use.
			*
			* fullname:        The resource record's full domain name.
			*
			* rrtype:          The resource record's type (e.g. PTR, SRV, etc) as defined in nameser.h.
			*
			* rrclass:         The class of the resource record, as defined in nameser.h (usually 1).
			*
			* rdata:           The raw rdata of the resource record.
			*
			*/
			static public void
			ReconfirmRecord
				(
				ServiceFlags	flags,
				int				interfaceIndex,
				String		*	fullname,
				int				rrtype,
				int				rrclass,
				Byte			rdata[]
				);
		};
	}
}