Home | History | Annotate | Download | only in DLL.NET
      1 /* -*- Mode: C; tab-width: 4 -*-
      2  *
      3  * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 
     18 // This is the main DLL file.
     19 
     20 #include "stdafx.h"
     21 
     22 #include "dnssd_NET.h"
     23 #include "DebugServices.h"
     24 #include "PString.h"
     25 
     26 
     27 using namespace System::Net::Sockets;
     28 using namespace System::Diagnostics;
     29 using namespace Apple;
     30 using namespace Apple::DNSSD;
     31 
     32 
     33 //===========================================================================================================================
     34 //	Constants
     35 //===========================================================================================================================
     36 
     37 #define	DEBUG_NAME	"[dnssd.NET] "
     38 
     39 //
     40 // ConvertToString
     41 //
     42 static String*
     43 ConvertToString(const char * utf8String)
     44 {
     45 	return __gc new String(utf8String, 0, strlen(utf8String), __gc new UTF8Encoding(true, true));
     46 }
     47 
     48 
     49 //
     50 // class ServiceRef
     51 //
     52 // ServiceRef serves as the base class for all DNSService operations.
     53 //
     54 // It manages the DNSServiceRef, and implements processing the
     55 // result
     56 //
     57 ServiceRef::ServiceRef(Object * callback)
     58 :
     59 	m_bDisposed(false),
     60 	m_callback(callback),
     61 	m_thread(NULL)
     62 {
     63 	m_impl = new ServiceRefImpl(this);
     64 }
     65 
     66 
     67 ServiceRef::~ServiceRef()
     68 {
     69 }
     70 
     71 
     72 //
     73 // StartThread
     74 //
     75 // Starts the main processing thread
     76 //
     77 void
     78 ServiceRef::StartThread()
     79 {
     80 	check( m_impl != NULL );
     81 
     82 	m_impl->SetupEvents();
     83 
     84 	m_thread		=	new Thread(new ThreadStart(this, &Apple::DNSSD::ServiceRef::ProcessingThread));
     85 	m_thread->Name	=	S"DNSService Thread";
     86 	m_thread->IsBackground = true;
     87 
     88 	m_thread->Start();
     89 }
     90 
     91 
     92 //
     93 // ProcessingThread
     94 //
     95 // The Thread class can only invoke methods in MC++ types.  So we
     96 // make a ProcessingThread method that forwards to the impl
     97 //
     98 void
     99 ServiceRef::ProcessingThread()
    100 {
    101 	m_impl->ProcessingThread();
    102 }
    103 
    104 
    105 //
    106 // Dispose
    107 //
    108 // Calls impl-Dispose().  This ultimately will call DNSServiceRefDeallocate()
    109 //
    110 void
    111 ServiceRef::Dispose()
    112 {
    113 	check(m_impl != NULL);
    114 	check(m_bDisposed == false);
    115 
    116 	if (!m_bDisposed)
    117 	{
    118 		m_bDisposed = true;
    119 
    120 		//
    121 		// Call Dispose.  This won't call DNSServiceRefDeallocate()
    122 		// necessarily. It depends on what thread this is being
    123 		// called in.
    124 		//
    125 		m_impl->Dispose();
    126 		m_impl = NULL;
    127 
    128 		m_thread = NULL;
    129 
    130 		GC::SuppressFinalize(this);
    131 	}
    132 }
    133 
    134 
    135 //
    136 // EnumerateDomainsDispatch
    137 //
    138 // Dispatch a reply to the delegate.
    139 //
    140 void
    141 ServiceRef::EnumerateDomainsDispatch
    142 						(
    143 						ServiceFlags	flags,
    144 						int				interfaceIndex,
    145 						ErrorCode		errorCode,
    146 						String		*	replyDomain
    147 						)
    148 {
    149 	if ((m_callback != NULL) && (m_impl != NULL))
    150 	{
    151 		DNSService::EnumerateDomainsReply * OnEnumerateDomainsReply = static_cast<DNSService::EnumerateDomainsReply*>(m_callback);
    152 		OnEnumerateDomainsReply(this, flags, interfaceIndex, errorCode, replyDomain);
    153 	}
    154 }
    155 
    156 
    157 //
    158 // RegisterDispatch
    159 //
    160 // Dispatch a reply to the delegate.
    161 //
    162 void
    163 ServiceRef::RegisterDispatch
    164 				(
    165 				ServiceFlags	flags,
    166 				ErrorCode		errorCode,
    167  				String		*	name,
    168 				String		*	regtype,
    169 				String		*	domain
    170 				)
    171 {
    172 	if ((m_callback != NULL) && (m_impl != NULL))
    173 	{
    174 		DNSService::RegisterReply * OnRegisterReply = static_cast<DNSService::RegisterReply*>(m_callback);
    175 		OnRegisterReply(this, flags, errorCode, name, regtype, domain);
    176 	}
    177 }
    178 
    179 
    180 //
    181 // BrowseDispatch
    182 //
    183 // Dispatch a reply to the delegate.
    184 //
    185 void
    186 ServiceRef::BrowseDispatch
    187 			(
    188 			ServiceFlags	flags,
    189 			int				interfaceIndex,
    190 			ErrorCode		errorCode,
    191 			String		*	serviceName,
    192 			String		*	regtype,
    193 			String		*	replyDomain
    194 			)
    195 {
    196 	if ((m_callback != NULL) && (m_impl != NULL))
    197 	{
    198 		DNSService::BrowseReply * OnBrowseReply = static_cast<DNSService::BrowseReply*>(m_callback);
    199 		OnBrowseReply(this, flags, interfaceIndex, errorCode, serviceName, regtype, replyDomain);
    200 	}
    201 }
    202 
    203 
    204 //
    205 // ResolveDispatch
    206 //
    207 // Dispatch a reply to the delegate.
    208 //
    209 void
    210 ServiceRef::ResolveDispatch
    211 			(
    212 			ServiceFlags	flags,
    213 			int				interfaceIndex,
    214 			ErrorCode		errorCode,
    215 			String		*	fullname,
    216 			String		*	hosttarget,
    217 			int				port,
    218 			Byte			txtRecord[]
    219 			)
    220 {
    221 	if ((m_callback != NULL) && (m_impl != NULL))
    222 	{
    223 		DNSService::ResolveReply * OnResolveReply = static_cast<DNSService::ResolveReply*>(m_callback);
    224 		OnResolveReply(this, flags, interfaceIndex, errorCode, fullname, hosttarget, port, txtRecord);
    225 	}
    226 }
    227 
    228 
    229 //
    230 // RegisterRecordDispatch
    231 //
    232 // Dispatch a reply to the delegate.
    233 //
    234 void
    235 ServiceRef::RegisterRecordDispatch
    236 				(
    237 				ServiceFlags	flags,
    238 				ErrorCode		errorCode,
    239 				RecordRef	*	record
    240 				)
    241 {
    242 	if ((m_callback != NULL) && (m_impl != NULL))
    243 	{
    244 		DNSService::RegisterRecordReply * OnRegisterRecordReply = static_cast<DNSService::RegisterRecordReply*>(m_callback);
    245 		OnRegisterRecordReply(this, flags, errorCode, record);
    246 	}
    247 }
    248 
    249 
    250 //
    251 // QueryRecordDispatch
    252 //
    253 // Dispatch a reply to the delegate.
    254 //
    255 void
    256 ServiceRef::QueryRecordDispatch
    257 					(
    258 					ServiceFlags	flags,
    259 					int				interfaceIndex,
    260 					ErrorCode		errorCode,
    261 					String		*	fullname,
    262 					int				rrtype,
    263 					int				rrclass,
    264 					Byte			rdata[],
    265 					int				ttl
    266 					)
    267 {
    268 	if ((m_callback != NULL) && (m_impl != NULL))
    269 	{
    270 		DNSService::QueryRecordReply * OnQueryRecordReply = static_cast<DNSService::QueryRecordReply*>(m_callback);
    271 		OnQueryRecordReply(this, flags, interfaceIndex, errorCode, fullname, rrtype, rrclass, rdata, ttl);
    272 	}
    273 }
    274 
    275 
    276 //
    277 // ServiceRefImpl::ServiceRefImpl()
    278 //
    279 // Constructs a new ServiceRefImpl.  We save the pointer to our enclosing
    280 // class in a gcroot handle.  This satisfies the garbage collector as
    281 // the outer class is a managed type
    282 //
    283 ServiceRef::ServiceRefImpl::ServiceRefImpl(ServiceRef * outer)
    284 :
    285 	m_socketEvent(NULL),
    286 	m_stopEvent(NULL),
    287 	m_disposed(false),
    288 	m_outer(outer),
    289 	m_ref(NULL)
    290 {
    291 	m_threadId = GetCurrentThreadId();
    292 }
    293 
    294 
    295 //
    296 // ServiceRefImpl::~ServiceRefImpl()
    297 //
    298 // Deallocate all resources associated with the ServiceRefImpl
    299 //
    300 ServiceRef::ServiceRefImpl::~ServiceRefImpl()
    301 {
    302 	if (m_socketEvent != NULL)
    303 	{
    304 		CloseHandle(m_socketEvent);
    305 		m_socketEvent = NULL;
    306 	}
    307 
    308 	if (m_stopEvent != NULL)
    309 	{
    310 		CloseHandle(m_stopEvent);
    311 		m_stopEvent = NULL;
    312 	}
    313 
    314 	if (m_ref != NULL)
    315 	{
    316 		DNSServiceRefDeallocate(m_ref);
    317 		m_ref = NULL;
    318 	}
    319 }
    320 
    321 
    322 //
    323 // ServiceRefImpl::SetupEvents()
    324 //
    325 // Setup the events necessary to manage multi-threaded dispatch
    326 // of DNSService Events
    327 //
    328 void
    329 ServiceRef::ServiceRefImpl::SetupEvents()
    330 {
    331 	check(m_ref != NULL);
    332 
    333 	m_socket		=	(SOCKET) DNSServiceRefSockFD(m_ref);
    334 	check(m_socket != INVALID_SOCKET);
    335 
    336 	m_socketEvent	=	CreateEvent(NULL, 0, 0, NULL);
    337 
    338 	if (m_socketEvent == NULL)
    339 	{
    340 		throw new DNSServiceException(Unknown);
    341 	}
    342 
    343 	int err = WSAEventSelect(m_socket, m_socketEvent, FD_READ|FD_CLOSE);
    344 
    345 	if (err != 0)
    346 	{
    347 		throw new DNSServiceException(Unknown);
    348 	}
    349 
    350 	m_stopEvent = CreateEvent(NULL, 0, 0, NULL);
    351 
    352 	if (m_stopEvent == NULL)
    353 	{
    354 		throw new DNSServiceException(Unknown);
    355 	}
    356 }
    357 
    358 
    359 //
    360 // ServiceRefImpl::ProcessingThread()
    361 //
    362 // Wait for socket events on the DNSServiceRefSockFD().  Also wait
    363 // for stop events
    364 //
    365 void
    366 ServiceRef::ServiceRefImpl::ProcessingThread()
    367 {
    368 	check( m_socketEvent != NULL );
    369 	check( m_stopEvent != NULL );
    370 	check( m_ref != NULL );
    371 
    372 	HANDLE handles[2];
    373 
    374 	handles[0] = m_socketEvent;
    375 	handles[1] = m_stopEvent;
    376 
    377 	while (m_disposed == false)
    378 	{
    379 		int ret = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
    380 
    381 		//
    382 		// it's a socket event
    383 		//
    384 		if (ret == WAIT_OBJECT_0)
    385 		{
    386 			DNSServiceProcessResult(m_ref);
    387 		}
    388 		//
    389 		// else it's a stop event
    390 		//
    391 		else if (ret == WAIT_OBJECT_0 + 1)
    392 		{
    393 			break;
    394 		}
    395 		else
    396 		{
    397 			//
    398 			// unexpected wait result
    399 			//
    400 			dlog( kDebugLevelWarning, DEBUG_NAME "%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__, ret );
    401 		}
    402 	}
    403 
    404 	delete this;
    405 }
    406 
    407 
    408 //
    409 // ServiceRefImpl::Dispose()
    410 //
    411 // Calls DNSServiceRefDeallocate()
    412 //
    413 void
    414 ServiceRef::ServiceRefImpl::Dispose()
    415 {
    416 	OSStatus	err;
    417 	BOOL		ok;
    418 
    419 	check(m_disposed == false);
    420 
    421 	m_disposed = true;
    422 
    423 	ok = SetEvent(m_stopEvent);
    424 	err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
    425 	require_noerr( err, exit );
    426 
    427 exit:
    428 
    429 	return;
    430 }
    431 
    432 
    433 //
    434 // ServiceRefImpl::EnumerateDomainsCallback()
    435 //
    436 // This is the callback from dnssd.dll.  We pass this up to our outer, managed type
    437 //
    438 void DNSSD_API
    439 ServiceRef::ServiceRefImpl::EnumerateDomainsCallback
    440 											(
    441 											DNSServiceRef			sdRef,
    442 											DNSServiceFlags			flags,
    443 											uint32_t				interfaceIndex,
    444 											DNSServiceErrorType		errorCode,
    445 											const char			*	replyDomain,
    446 											void				*	context
    447 											)
    448 {
    449 	ServiceRef::ServiceRefImpl * self = static_cast<ServiceRef::ServiceRefImpl*>(context);
    450 
    451 	check( self != NULL );
    452 	check( self->m_outer != NULL );
    453 
    454 	if (self->m_disposed == false)
    455 	{
    456 		self->m_outer->EnumerateDomainsDispatch((ServiceFlags) flags, interfaceIndex, (ErrorCode) errorCode, ConvertToString(replyDomain));
    457 	}
    458 }
    459 
    460 
    461 //
    462 // ServiceRefImpl::RegisterCallback()
    463 //
    464 // This is the callback from dnssd.dll.  We pass this up to our outer, managed type
    465 //
    466 void DNSSD_API
    467 ServiceRef::ServiceRefImpl::RegisterCallback
    468 							(
    469 							DNSServiceRef			sdRef,
    470 							DNSServiceFlags			flags,
    471 							DNSServiceErrorType		errorCode,
    472 							const char			*	name,
    473 							const char			*	regtype,
    474 							const char			*	domain,
    475 							void				*	context
    476 							)
    477 {
    478 	ServiceRef::ServiceRefImpl * self = static_cast<ServiceRef::ServiceRefImpl*>(context);
    479 
    480 	check( self != NULL );
    481 	check( self->m_outer != NULL );
    482 
    483 	if (self->m_disposed == false)
    484 	{
    485 		self->m_outer->RegisterDispatch((ServiceFlags) flags, (ErrorCode) errorCode, ConvertToString(name), ConvertToString(regtype), ConvertToString(domain));
    486 	}
    487 }
    488 
    489 
    490 //
    491 // ServiceRefImpl::BrowseCallback()
    492 //
    493 // This is the callback from dnssd.dll.  We pass this up to our outer, managed type
    494 //
    495 void DNSSD_API
    496 ServiceRef::ServiceRefImpl::BrowseCallback
    497 							(
    498 							DNSServiceRef			sdRef,
    499    							DNSServiceFlags			flags,
    500 							uint32_t				interfaceIndex,
    501 							DNSServiceErrorType		errorCode,
    502 							const char			*	serviceName,
    503 							const char			*	regtype,
    504 							const char			*	replyDomain,
    505 							void				*	context
    506 							)
    507 {
    508 	ServiceRef::ServiceRefImpl * self = static_cast<ServiceRef::ServiceRefImpl*>(context);
    509 
    510 	check( self != NULL );
    511 	check( self->m_outer != NULL );
    512 
    513 	if (self->m_disposed == false)
    514 	{
    515 		self->m_outer->BrowseDispatch((ServiceFlags) flags, interfaceIndex, (ErrorCode) errorCode, ConvertToString(serviceName), ConvertToString(regtype), ConvertToString(replyDomain));
    516 	}
    517 }
    518 
    519 
    520 //
    521 // ServiceRefImpl::ResolveCallback()
    522 //
    523 // This is the callback from dnssd.dll.  We pass this up to our outer, managed type
    524 //
    525 void DNSSD_API
    526 ServiceRef::ServiceRefImpl::ResolveCallback
    527 							(
    528 							DNSServiceRef			sdRef,
    529 							DNSServiceFlags			flags,
    530 							uint32_t				interfaceIndex,
    531 							DNSServiceErrorType		errorCode,
    532 							const char			*	fullname,
    533 							const char			*	hosttarget,
    534 							uint16_t				notAnIntPort,
    535 							uint16_t				txtLen,
    536 							const char			*	txtRecord,
    537 							void				*	context
    538 							)
    539 {
    540 	ServiceRef::ServiceRefImpl * self = static_cast<ServiceRef::ServiceRefImpl*>(context);
    541 
    542 	check( self != NULL );
    543 	check( self->m_outer != NULL );
    544 
    545 	if (self->m_disposed == false)
    546 	{
    547 		Byte txtRecordBytes[];
    548 
    549 		txtRecordBytes = NULL;
    550 
    551 		if (txtLen > 0)
    552 		{
    553 			//
    554 			// copy raw memory into managed byte array
    555 			//
    556 			txtRecordBytes		=	new Byte[txtLen];
    557 			Byte __pin	*	p	=	&txtRecordBytes[0];
    558 			memcpy(p, txtRecord, txtLen);
    559 		}
    560 
    561 		self->m_outer->ResolveDispatch((ServiceFlags) flags, interfaceIndex, (ErrorCode) errorCode, ConvertToString(fullname), ConvertToString(hosttarget), ntohs(notAnIntPort), txtRecordBytes);
    562 	}
    563 }
    564 
    565 
    566 //
    567 // ServiceRefImpl::RegisterRecordCallback()
    568 //
    569 // This is the callback from dnssd.dll.  We pass this up to our outer, managed type
    570 //
    571 void DNSSD_API
    572 ServiceRef::ServiceRefImpl::RegisterRecordCallback
    573 								(
    574 								DNSServiceRef		sdRef,
    575 								DNSRecordRef		rrRef,
    576 								DNSServiceFlags		flags,
    577 								DNSServiceErrorType	errorCode,
    578 								void			*	context
    579 								)
    580 {
    581 	ServiceRef::ServiceRefImpl * self = static_cast<ServiceRef::ServiceRefImpl*>(context);
    582 
    583 	check( self != NULL );
    584 	check( self->m_outer != NULL );
    585 
    586 	if (self->m_disposed == false)
    587 	{
    588 		RecordRef * record = NULL;
    589 
    590 		if (errorCode == 0)
    591 		{
    592 			record = new RecordRef;
    593 
    594 			record->m_impl->m_ref = rrRef;
    595 		}
    596 
    597 		self->m_outer->RegisterRecordDispatch((ServiceFlags) flags, (ErrorCode) errorCode, record);
    598 	}
    599 }
    600 
    601 
    602 //
    603 // ServiceRefImpl::QueryRecordCallback()
    604 //
    605 // This is the callback from dnssd.dll.  We pass this up to our outer, managed type
    606 //
    607 void DNSSD_API
    608 ServiceRef::ServiceRefImpl::QueryRecordCallback
    609 								(
    610 								DNSServiceRef			DNSServiceRef,
    611 								DNSServiceFlags			flags,
    612 								uint32_t				interfaceIndex,
    613 								DNSServiceErrorType		errorCode,
    614 								const char			*	fullname,
    615 								uint16_t				rrtype,
    616 								uint16_t				rrclass,
    617 								uint16_t				rdlen,
    618 								const void			*	rdata,
    619 								uint32_t				ttl,
    620 								void				*	context
    621 								)
    622 {
    623 	ServiceRef::ServiceRefImpl * self = static_cast<ServiceRef::ServiceRefImpl*>(context);
    624 
    625 	check( self != NULL );
    626 	check( self->m_outer != NULL );
    627 
    628 	if (self->m_disposed == false)
    629 	{
    630 		Byte rdataBytes[];
    631 
    632 		if (rdlen)
    633 		{
    634 			rdataBytes			=	new Byte[rdlen];
    635 			Byte __pin * p		=	&rdataBytes[0];
    636 			memcpy(p, rdata, rdlen);
    637 		}
    638 
    639 		self->m_outer->QueryRecordDispatch((ServiceFlags) flags, (int) interfaceIndex, (ErrorCode) errorCode, ConvertToString(fullname), rrtype, rrclass, rdataBytes, ttl);
    640 	}
    641 }
    642 
    643 
    644 /*
    645  * EnumerateDomains()
    646  *
    647  * This maps to DNSServiceEnumerateDomains().  Returns an
    648  * initialized ServiceRef on success, throws an exception
    649  * on failure.
    650  */
    651 ServiceRef*
    652 DNSService::EnumerateDomains
    653 		(
    654 		int							flags,
    655 		int							interfaceIndex,
    656 		EnumerateDomainsReply	*	callback
    657 		)
    658 {
    659 	ServiceRef * sdRef = new ServiceRef(callback);
    660 	int			 err;
    661 
    662 	err = DNSServiceEnumerateDomains(&sdRef->m_impl->m_ref, flags, interfaceIndex, ServiceRef::ServiceRefImpl::EnumerateDomainsCallback, sdRef->m_impl);
    663 
    664 	if (err != 0)
    665 	{
    666 		throw new DNSServiceException(err);
    667 	}
    668 
    669 	sdRef->StartThread();
    670 
    671 	return sdRef;
    672 }
    673 
    674 
    675 /*
    676  * Register()
    677  *
    678  * This maps to DNSServiceRegister().  Returns an
    679  * initialized ServiceRef on success, throws an exception
    680  * on failure.
    681  */
    682 ServiceRef*
    683 DNSService::Register
    684 				(
    685 				int					flags,
    686 				int					interfaceIndex,
    687 				String			*	name,
    688 				String			*	regtype,
    689 				String			*	domain,
    690 				String			*	host,
    691 				int					port,
    692 				Byte				txtRecord[],
    693 				RegisterReply	*	callback
    694 				)
    695 {
    696 	ServiceRef	*	sdRef	=	new ServiceRef(callback);
    697 	PString		*	pName	=	new PString(name);
    698 	PString		*	pType	=	new PString(regtype);
    699 	PString		*	pDomain =	new PString(domain);
    700 	PString		*	pHost	=	new PString(host);
    701 	int				len		=	0;
    702 	Byte __pin	*	p		=	NULL;
    703 	void		*	v		=	NULL;
    704 
    705 	if ((txtRecord != NULL) && (txtRecord->Length > 0))
    706 	{
    707 		len		= txtRecord->Length;
    708 		p		= &txtRecord[0];
    709 		v		= (void*) p;
    710 	}
    711 
    712 	int err = DNSServiceRegister(&sdRef->m_impl->m_ref, flags, interfaceIndex, pName->c_str(), pType->c_str(), pDomain->c_str(), pHost->c_str(), htons(port), len, v, ServiceRef::ServiceRefImpl::RegisterCallback, sdRef->m_impl );
    713 
    714 	if (err != 0)
    715 	{
    716 		throw new DNSServiceException(err);
    717 	}
    718 
    719 	sdRef->StartThread();
    720 
    721 	return sdRef;
    722 }
    723 
    724 
    725 /*
    726  * AddRecord()
    727  *
    728  * This maps to DNSServiceAddRecord().  Returns an
    729  * initialized ServiceRef on success, throws an exception
    730  * on failure.
    731  */
    732 RecordRef*
    733 DNSService::AddRecord
    734 				(
    735 				ServiceRef	*	sdRef,
    736 				int				flags,
    737 				int				rrtype,
    738 				Byte			rdata[],
    739 				int				ttl
    740 				)
    741 {
    742 	int				len		=	0;
    743 	Byte __pin	*	p		=	NULL;
    744 	void		*	v		=	NULL;
    745 
    746 	if ((rdata != NULL) && (rdata->Length > 0))
    747 	{
    748 		len = rdata->Length;
    749 		p	= &rdata[0];
    750 		v	= (void*) p;
    751 	}
    752 
    753 	RecordRef * record = new RecordRef;
    754 
    755 	int err = DNSServiceAddRecord(sdRef->m_impl->m_ref, &record->m_impl->m_ref, flags, rrtype, len, v, ttl);
    756 
    757 	if (err != 0)
    758 	{
    759 		throw new DNSServiceException(err);
    760 	}
    761 
    762 	return record;
    763 }
    764 
    765 
    766 /*
    767  * UpdateRecord()
    768  *
    769  * This maps to DNSServiceUpdateRecord().  Returns an
    770  * initialized ServiceRef on success, throws an exception
    771  * on failure.
    772  */
    773 void
    774 DNSService::UpdateRecord
    775 				(
    776 				ServiceRef	*	sdRef,
    777 				RecordRef	*	record,
    778 				int				flags,
    779 				Byte			rdata[],
    780 				int				ttl
    781 				)
    782 {
    783 	int				len		=	0;
    784 	Byte __pin	*	p		=	NULL;
    785 	void		*	v		=	NULL;
    786 
    787 	if ((rdata != NULL) && (rdata->Length > 0))
    788 	{
    789 		len	= rdata->Length;
    790 		p	= &rdata[0];
    791 		v	= (void*) p;
    792 	}
    793 
    794 	int err = DNSServiceUpdateRecord(sdRef->m_impl->m_ref, record ? record->m_impl->m_ref : NULL, flags, len, v, ttl);
    795 
    796 	if (err != 0)
    797 	{
    798 		throw new DNSServiceException(err);
    799 	}
    800 }
    801 
    802 
    803 /*
    804  * RemoveRecord()
    805  *
    806  * This maps to DNSServiceRemoveRecord().  Returns an
    807  * initialized ServiceRef on success, throws an exception
    808  * on failure.
    809  */
    810 void
    811 DNSService::RemoveRecord
    812 		(
    813 		ServiceRef	*	sdRef,
    814 		RecordRef	*	record,
    815 		int				flags
    816 		)
    817 {
    818 	int err = DNSServiceRemoveRecord(sdRef->m_impl->m_ref, record->m_impl->m_ref, flags);
    819 
    820 	if (err != 0)
    821 	{
    822 		throw new DNSServiceException(err);
    823 	}
    824 }
    825 
    826 
    827 /*
    828  * Browse()
    829  *
    830  * This maps to DNSServiceBrowse().  Returns an
    831  * initialized ServiceRef on success, throws an exception
    832  * on failure.
    833  */
    834 ServiceRef*
    835 DNSService::Browse
    836 	(
    837 	int				flags,
    838 	int				interfaceIndex,
    839 	String		*	regtype,
    840 	String		*	domain,
    841 	BrowseReply	*	callback
    842 	)
    843 {
    844 	ServiceRef	*	sdRef	= new ServiceRef(callback);
    845 	PString		*	pType	= new PString(regtype);
    846 	PString		*	pDomain	= new PString(domain);
    847 
    848 	int err = DNSServiceBrowse(&sdRef->m_impl->m_ref, flags, interfaceIndex, pType->c_str(), pDomain->c_str(),(DNSServiceBrowseReply) ServiceRef::ServiceRefImpl::BrowseCallback, sdRef->m_impl);
    849 
    850 	if (err != 0)
    851 	{
    852 		throw new DNSServiceException(err);
    853 	}
    854 
    855 	sdRef->StartThread();
    856 
    857 	return sdRef;
    858 }
    859 
    860 
    861 /*
    862  * Resolve()
    863  *
    864  * This maps to DNSServiceResolve().  Returns an
    865  * initialized ServiceRef on success, throws an exception
    866  * on failure.
    867  */
    868 ServiceRef*
    869 DNSService::Resolve
    870 	(
    871 	int					flags,
    872 	int					interfaceIndex,
    873 	String			*	name,
    874 	String			*	regtype,
    875 	String			*	domain,
    876 	ResolveReply	*	callback
    877 	)
    878 {
    879 	ServiceRef	*	sdRef	= new ServiceRef(callback);
    880 	PString		*	pName	= new PString(name);
    881 	PString		*	pType	= new PString(regtype);
    882 	PString		*	pDomain	= new PString(domain);
    883 
    884 	int err = DNSServiceResolve(&sdRef->m_impl->m_ref, flags, interfaceIndex, pName->c_str(), pType->c_str(), pDomain->c_str(),(DNSServiceResolveReply) ServiceRef::ServiceRefImpl::ResolveCallback, sdRef->m_impl);
    885 
    886 	if (err != 0)
    887 	{
    888 		throw new DNSServiceException(err);
    889 	}
    890 
    891 	sdRef->StartThread();
    892 
    893 	return sdRef;
    894 }
    895 
    896 
    897 /*
    898  * CreateConnection()
    899  *
    900  * This maps to DNSServiceCreateConnection().  Returns an
    901  * initialized ServiceRef on success, throws an exception
    902  * on failure.
    903  */
    904 ServiceRef*
    905 DNSService::CreateConnection
    906 			(
    907 			RegisterRecordReply * callback
    908 			)
    909 {
    910 	ServiceRef * sdRef = new ServiceRef(callback);
    911 
    912 	int err = DNSServiceCreateConnection(&sdRef->m_impl->m_ref);
    913 
    914 	if (err != 0)
    915 	{
    916 		throw new DNSServiceException(err);
    917 	}
    918 
    919 	sdRef->StartThread();
    920 
    921 	return sdRef;
    922 }
    923 
    924 
    925 /*
    926  * RegisterRecord()
    927  *
    928  * This maps to DNSServiceRegisterRecord().  Returns an
    929  * initialized ServiceRef on success, throws an exception
    930  * on failure.
    931  */
    932 
    933 RecordRef*
    934 DNSService::RegisterRecord
    935 			(
    936 			ServiceRef			*	sdRef,
    937 			ServiceFlags			flags,
    938 			int						interfaceIndex,
    939 			String				*	fullname,
    940 			int						rrtype,
    941 			int						rrclass,
    942 			Byte					rdata[],
    943 			int						ttl
    944 			)
    945 {
    946 	RecordRef	*	record	= new RecordRef;
    947 	int				len		= 0;
    948 	Byte __pin	*	p		= NULL;
    949 	void		*	v		= NULL;
    950 
    951 	PString * pFullname = new PString(fullname);
    952 
    953 	if ((rdata != NULL) && (rdata->Length > 0))
    954 	{
    955 		len		= rdata->Length;
    956 		p		= &rdata[0];
    957 		v		= (void*) p;
    958 	}
    959 
    960 	int err = DNSServiceRegisterRecord(sdRef->m_impl->m_ref, &record->m_impl->m_ref, flags, interfaceIndex, pFullname->c_str(), rrtype, rrclass, len, v, ttl, (DNSServiceRegisterRecordReply) ServiceRef::ServiceRefImpl::RegisterRecordCallback, sdRef->m_impl);
    961 
    962 	if (err != 0)
    963 	{
    964 		throw new DNSServiceException(err);
    965 	}
    966 
    967 	return record;
    968 }
    969 
    970 /*
    971  * QueryRecord()
    972  *
    973  * This maps to DNSServiceQueryRecord().  Returns an
    974  * initialized ServiceRef on success, throws an exception
    975  * on failure.
    976  */
    977 ServiceRef*
    978 DNSService::QueryRecord
    979 		(
    980 		ServiceFlags			flags,
    981 		int						interfaceIndex,
    982 		String				*	fullname,
    983 		int						rrtype,
    984 		int						rrclass,
    985 		QueryRecordReply	*	callback
    986 		)
    987 {
    988 	ServiceRef	*	sdRef		= new ServiceRef(callback);
    989 	PString		*	pFullname	= new PString(fullname);
    990 
    991 	int err = DNSServiceQueryRecord(&sdRef->m_impl->m_ref, flags, interfaceIndex, pFullname->c_str(), rrtype, rrclass, (DNSServiceQueryRecordReply) ServiceRef::ServiceRefImpl::QueryRecordCallback, sdRef->m_impl);
    992 
    993 	if (err != 0)
    994 	{
    995 		throw new DNSServiceException(err);
    996 	}
    997 
    998 	sdRef->StartThread();
    999 
   1000 	return sdRef;
   1001 }
   1002 
   1003 
   1004 /*
   1005  * ReconfirmRecord()
   1006  *
   1007  * This maps to DNSServiceReconfirmRecord().  Returns an
   1008  * initialized ServiceRef on success, throws an exception
   1009  * on failure.
   1010  */
   1011 void
   1012 DNSService::ReconfirmRecord
   1013 		(
   1014 		ServiceFlags	flags,
   1015 		int				interfaceIndex,
   1016 		String		*	fullname,
   1017 		int				rrtype,
   1018 		int				rrclass,
   1019 		Byte			rdata[]
   1020 		)
   1021 {
   1022 	int				len	= 0;
   1023 	Byte __pin	*	p	= NULL;
   1024 	void		*	v	= NULL;
   1025 
   1026 	PString * pFullname = new PString(fullname);
   1027 
   1028 	if ((rdata != NULL) && (rdata->Length > 0))
   1029 	{
   1030 		len	= rdata->Length;
   1031 		p	= &rdata[0];
   1032 		v	= (void*) p;
   1033 	}
   1034 
   1035 	DNSServiceReconfirmRecord(flags, interfaceIndex, pFullname->c_str(), rrtype, rrclass, len, v);
   1036 }
   1037 
   1038 
   1039 void
   1040 TextRecord::SetValue
   1041 		(
   1042 		String	*	key,
   1043 		Byte		value[]            /* may be NULL */
   1044 		)
   1045 {
   1046 	PString			*	pKey = new PString(key);
   1047 	int					len		=	0;
   1048 	Byte __pin		*	p		=	NULL;
   1049 	void			*	v		=	NULL;
   1050 	DNSServiceErrorType	err;
   1051 
   1052 	if (value && (value->Length > 0))
   1053 	{
   1054 		len	=	value->Length;
   1055 		p	=	&value[0];
   1056 		v	=	(void*) p;
   1057 	}
   1058 
   1059 	err = TXTRecordSetValue(&m_impl->m_ref, pKey->c_str(), len, v);
   1060 
   1061 	if (err != 0)
   1062 	{
   1063 		throw new DNSServiceException(err);
   1064 	}
   1065 }
   1066 
   1067 
   1068 void
   1069 TextRecord::RemoveValue
   1070 		(
   1071 		String	*	key
   1072 		)
   1073 {
   1074 	PString			*	pKey = new PString(key);
   1075 	DNSServiceErrorType	err;
   1076 
   1077 	err = TXTRecordRemoveValue(&m_impl->m_ref, pKey->c_str());
   1078 
   1079 	if (err != 0)
   1080 	{
   1081 		throw new DNSServiceException(err);
   1082 	}
   1083 }
   1084 
   1085 
   1086 int
   1087 TextRecord::GetLength
   1088 		(
   1089 		)
   1090 {
   1091 	return TXTRecordGetLength(&m_impl->m_ref);
   1092 }
   1093 
   1094 
   1095 Byte
   1096 TextRecord::GetBytes
   1097 		(
   1098 		) __gc[]
   1099 {
   1100 	const void	*	noGCBytes = NULL;
   1101 	Byte			gcBytes[] = NULL;
   1102 
   1103 	noGCBytes		=	TXTRecordGetBytesPtr(&m_impl->m_ref);
   1104 	int			len	=	GetLength();
   1105 
   1106 	if (noGCBytes && len)
   1107 	{
   1108 		gcBytes				=	new Byte[len];
   1109 		Byte __pin	*	p	=	&gcBytes[0];
   1110 		memcpy(p, noGCBytes, len);
   1111 	}
   1112 
   1113 	return gcBytes;
   1114 }
   1115 
   1116 
   1117 bool
   1118 TextRecord::ContainsKey
   1119 		(
   1120 		Byte		txtRecord[],
   1121 		String	*	key
   1122 		)
   1123 {
   1124 	PString		*	pKey	= new PString(key);
   1125 	Byte __pin	*	p		= &txtRecord[0];
   1126 
   1127 	return (TXTRecordContainsKey(txtRecord->Length, p, pKey->c_str()) > 0) ? true : false;
   1128 }
   1129 
   1130 
   1131 Byte
   1132 TextRecord::GetValueBytes
   1133 		(
   1134 		Byte		txtRecord[],
   1135 		String	*	key
   1136 		) __gc[]
   1137 {
   1138 	uint8_t			valueLen;
   1139 	Byte			ret[]	= NULL;
   1140 	PString		*	pKey	= new PString(key);
   1141 	Byte __pin	*	p1		= &txtRecord[0];
   1142 	const void	*	v;
   1143 
   1144 	v = TXTRecordGetValuePtr(txtRecord->Length, p1, pKey->c_str(), &valueLen);
   1145 
   1146 	if (v != NULL)
   1147 	{
   1148 		ret					= new Byte[valueLen];
   1149 		Byte __pin	*	p2	= &ret[0];
   1150 
   1151 		memcpy(p2, v, valueLen);
   1152 	}
   1153 
   1154 	return ret;
   1155 }
   1156 
   1157 
   1158 int
   1159 TextRecord::GetCount
   1160 		(
   1161 		Byte txtRecord[]
   1162 		)
   1163 {
   1164 	Byte __pin	*	p	= &txtRecord[0];
   1165 
   1166 	return TXTRecordGetCount(txtRecord->Length, p);
   1167 }
   1168 
   1169 
   1170 Byte
   1171 TextRecord::GetItemAtIndex
   1172 		(
   1173 		Byte				txtRecord[],
   1174 		int					index,
   1175 		[Out] String	**	key
   1176 		) __gc[]
   1177 {
   1178 	char				keyBuf[255];
   1179 	uint8_t				keyBufLen = 255;
   1180 	uint8_t				valueLen;
   1181 	void			*	value;
   1182 	Byte				ret[]	= NULL;
   1183 	DNSServiceErrorType	err;
   1184 	Byte __pin		*	p1		= &txtRecord[0];
   1185 
   1186 
   1187 	err = TXTRecordGetItemAtIndex(txtRecord->Length, p1, index, keyBufLen, keyBuf, &valueLen, (const void**) &value);
   1188 
   1189 	if (err != 0)
   1190 	{
   1191 		throw new DNSServiceException(err);
   1192 	}
   1193 
   1194 	*key = ConvertToString(keyBuf);
   1195 
   1196 	if (valueLen)
   1197 	{
   1198 		ret					= new Byte[valueLen];
   1199 		Byte __pin	*	p2	= &ret[0];
   1200 
   1201 		memcpy(p2, value, valueLen);
   1202 	}
   1203 
   1204 	return ret;
   1205 }
   1206 
   1207 
   1208 //
   1209 // DNSServiceException::DNSServiceException()
   1210 //
   1211 // Constructs an exception with an error code
   1212 //
   1213 DNSServiceException::DNSServiceException
   1214 				(
   1215 				int _err
   1216 				)
   1217 :
   1218 	err(_err)
   1219 {
   1220 }
   1221 
   1222 
   1223 //
   1224 // This version of the constructor is useful for instances in which
   1225 // an inner exception is thrown, caught, and then a new exception
   1226 // is thrown in it's place
   1227 //
   1228 DNSServiceException::DNSServiceException
   1229 				(
   1230 				String				*	message,
   1231 				System::Exception	*	innerException
   1232 				)
   1233 {
   1234 }
   1235