#include "stdafx.h"
#include "dnssd_NET.h"
#include "DebugServices.h"
#include "PString.h"
using namespace System::Net::Sockets;
using namespace System::Diagnostics;
using namespace Apple;
using namespace Apple::DNSSD;
#define DEBUG_NAME "[dnssd.NET] "
static String*
ConvertToString(const char * utf8String)
{
return __gc new String(utf8String, 0, strlen(utf8String), __gc new UTF8Encoding(true, true));
}
ServiceRef::ServiceRef(Object * callback)
:
m_bDisposed(false),
m_callback(callback),
m_thread(NULL)
{
m_impl = new ServiceRefImpl(this);
}
ServiceRef::~ServiceRef()
{
}
void
ServiceRef::StartThread()
{
check( m_impl != NULL );
m_impl->SetupEvents();
m_thread = new Thread(new ThreadStart(this, ProcessingThread));
m_thread->Name = S"DNSService Thread";
m_thread->IsBackground = true;
m_thread->Start();
}
void
ServiceRef::ProcessingThread()
{
m_impl->ProcessingThread();
}
void
ServiceRef::Dispose()
{
check(m_impl != NULL);
check(m_bDisposed == false);
if (!m_bDisposed)
{
m_bDisposed = true;
m_impl->Dispose();
m_impl = NULL;
m_thread = NULL;
GC::SuppressFinalize(this);
}
}
void
ServiceRef::EnumerateDomainsDispatch
(
ServiceFlags flags,
int interfaceIndex,
ErrorCode errorCode,
String * replyDomain
)
{
if ((m_callback != NULL) && (m_impl != NULL))
{
DNSService::EnumerateDomainsReply * OnEnumerateDomainsReply = static_cast<DNSService::EnumerateDomainsReply*>(m_callback);
OnEnumerateDomainsReply(this, flags, interfaceIndex, errorCode, replyDomain);
}
}
void
ServiceRef::RegisterDispatch
(
ServiceFlags flags,
ErrorCode errorCode,
String * name,
String * regtype,
String * domain
)
{
if ((m_callback != NULL) && (m_impl != NULL))
{
DNSService::RegisterReply * OnRegisterReply = static_cast<DNSService::RegisterReply*>(m_callback);
OnRegisterReply(this, flags, errorCode, name, regtype, domain);
}
}
void
ServiceRef::BrowseDispatch
(
ServiceFlags flags,
int interfaceIndex,
ErrorCode errorCode,
String * serviceName,
String * regtype,
String * replyDomain
)
{
if ((m_callback != NULL) && (m_impl != NULL))
{
DNSService::BrowseReply * OnBrowseReply = static_cast<DNSService::BrowseReply*>(m_callback);
OnBrowseReply(this, flags, interfaceIndex, errorCode, serviceName, regtype, replyDomain);
}
}
void
ServiceRef::ResolveDispatch
(
ServiceFlags flags,
int interfaceIndex,
ErrorCode errorCode,
String * fullname,
String * hosttarget,
int port,
Byte txtRecord[]
)
{
if ((m_callback != NULL) && (m_impl != NULL))
{
DNSService::ResolveReply * OnResolveReply = static_cast<DNSService::ResolveReply*>(m_callback);
OnResolveReply(this, flags, interfaceIndex, errorCode, fullname, hosttarget, port, txtRecord);
}
}
void
ServiceRef::RegisterRecordDispatch
(
ServiceFlags flags,
ErrorCode errorCode,
RecordRef * record
)
{
if ((m_callback != NULL) && (m_impl != NULL))
{
DNSService::RegisterRecordReply * OnRegisterRecordReply = static_cast<DNSService::RegisterRecordReply*>(m_callback);
OnRegisterRecordReply(this, flags, errorCode, record);
}
}
void
ServiceRef::QueryRecordDispatch
(
ServiceFlags flags,
int interfaceIndex,
ErrorCode errorCode,
String * fullname,
int rrtype,
int rrclass,
Byte rdata[],
int ttl
)
{
if ((m_callback != NULL) && (m_impl != NULL))
{
DNSService::QueryRecordReply * OnQueryRecordReply = static_cast<DNSService::QueryRecordReply*>(m_callback);
OnQueryRecordReply(this, flags, interfaceIndex, errorCode, fullname, rrtype, rrclass, rdata, ttl);
}
}
ServiceRef::ServiceRefImpl::ServiceRefImpl(ServiceRef * outer)
:
m_socketEvent(NULL),
m_stopEvent(NULL),
m_disposed(false),
m_outer(outer),
m_ref(NULL)
{
m_threadId = GetCurrentThreadId();
}
ServiceRef::ServiceRefImpl::~ServiceRefImpl()
{
if (m_socketEvent != NULL)
{
CloseHandle(m_socketEvent);
m_socketEvent = NULL;
}
if (m_stopEvent != NULL)
{
CloseHandle(m_stopEvent);
m_stopEvent = NULL;
}
if (m_ref != NULL)
{
DNSServiceRefDeallocate(m_ref);
m_ref = NULL;
}
}
void
ServiceRef::ServiceRefImpl::SetupEvents()
{
check(m_ref != NULL);
m_socket = (SOCKET) DNSServiceRefSockFD(m_ref);
check(m_socket != INVALID_SOCKET);
m_socketEvent = CreateEvent(NULL, 0, 0, NULL);
if (m_socketEvent == NULL)
{
throw new DNSServiceException(Unknown);
}
int err = WSAEventSelect(m_socket, m_socketEvent, FD_READ|FD_CLOSE);
if (err != 0)
{
throw new DNSServiceException(Unknown);
}
m_stopEvent = CreateEvent(NULL, 0, 0, NULL);
if (m_stopEvent == NULL)
{
throw new DNSServiceException(Unknown);
}
}
void
ServiceRef::ServiceRefImpl::ProcessingThread()
{
check( m_socketEvent != NULL );
check( m_stopEvent != NULL );
check( m_ref != NULL );
HANDLE handles[2];
handles[0] = m_socketEvent;
handles[1] = m_stopEvent;
while (m_disposed == false)
{
int ret = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
if (ret == WAIT_OBJECT_0)
{
DNSServiceProcessResult(m_ref);
}
else if (ret == WAIT_OBJECT_0 + 1)
{
break;
}
else
{
dlog( kDebugLevelWarning, DEBUG_NAME "%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__, ret );
}
}
delete this;
}
void
ServiceRef::ServiceRefImpl::Dispose()
{
OSStatus err;
BOOL ok;
check(m_disposed == false);
m_disposed = true;
ok = SetEvent(m_stopEvent);
err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
require_noerr( err, exit );
exit:
return;
}
void DNSSD_API
ServiceRef::ServiceRefImpl::EnumerateDomainsCallback
(
DNSServiceRef sdRef,
DNSServiceFlags flags,
uint32_t interfaceIndex,
DNSServiceErrorType errorCode,
const char * replyDomain,
void * context
)
{
ServiceRef::ServiceRefImpl * self = static_cast<ServiceRef::ServiceRefImpl*>(context);
check( self != NULL );
check( self->m_outer != NULL );
if (self->m_disposed == false)
{
self->m_outer->EnumerateDomainsDispatch((ServiceFlags) flags, interfaceIndex, (ErrorCode) errorCode, ConvertToString(replyDomain));
}
}
void DNSSD_API
ServiceRef::ServiceRefImpl::RegisterCallback
(
DNSServiceRef sdRef,
DNSServiceFlags flags,
DNSServiceErrorType errorCode,
const char * name,
const char * regtype,
const char * domain,
void * context
)
{
ServiceRef::ServiceRefImpl * self = static_cast<ServiceRef::ServiceRefImpl*>(context);
check( self != NULL );
check( self->m_outer != NULL );
if (self->m_disposed == false)
{
self->m_outer->RegisterDispatch((ServiceFlags) flags, (ErrorCode) errorCode, ConvertToString(name), ConvertToString(regtype), ConvertToString(domain));
}
}
void DNSSD_API
ServiceRef::ServiceRefImpl::BrowseCallback
(
DNSServiceRef sdRef,
DNSServiceFlags flags,
uint32_t interfaceIndex,
DNSServiceErrorType errorCode,
const char * serviceName,
const char * regtype,
const char * replyDomain,
void * context
)
{
ServiceRef::ServiceRefImpl * self = static_cast<ServiceRef::ServiceRefImpl*>(context);
check( self != NULL );
check( self->m_outer != NULL );
if (self->m_disposed == false)
{
self->m_outer->BrowseDispatch((ServiceFlags) flags, interfaceIndex, (ErrorCode) errorCode, ConvertToString(serviceName), ConvertToString(regtype), ConvertToString(replyDomain));
}
}
void DNSSD_API
ServiceRef::ServiceRefImpl::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
)
{
ServiceRef::ServiceRefImpl * self = static_cast<ServiceRef::ServiceRefImpl*>(context);
check( self != NULL );
check( self->m_outer != NULL );
if (self->m_disposed == false)
{
Byte txtRecordBytes[];
txtRecordBytes = NULL;
if (txtLen > 0)
{
txtRecordBytes = new Byte[txtLen];
Byte __pin * p = &txtRecordBytes[0];
memcpy(p, txtRecord, txtLen);
}
self->m_outer->ResolveDispatch((ServiceFlags) flags, interfaceIndex, (ErrorCode) errorCode, ConvertToString(fullname), ConvertToString(hosttarget), ntohs(notAnIntPort), txtRecordBytes);
}
}
void DNSSD_API
ServiceRef::ServiceRefImpl::RegisterRecordCallback
(
DNSServiceRef sdRef,
DNSRecordRef rrRef,
DNSServiceFlags flags,
DNSServiceErrorType errorCode,
void * context
)
{
ServiceRef::ServiceRefImpl * self = static_cast<ServiceRef::ServiceRefImpl*>(context);
check( self != NULL );
check( self->m_outer != NULL );
if (self->m_disposed == false)
{
RecordRef * record = NULL;
if (errorCode == 0)
{
record = new RecordRef;
record->m_impl->m_ref = rrRef;
}
self->m_outer->RegisterRecordDispatch((ServiceFlags) flags, (ErrorCode) errorCode, record);
}
}
void DNSSD_API
ServiceRef::ServiceRefImpl::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
)
{
ServiceRef::ServiceRefImpl * self = static_cast<ServiceRef::ServiceRefImpl*>(context);
check( self != NULL );
check( self->m_outer != NULL );
if (self->m_disposed == false)
{
Byte rdataBytes[];
if (rdlen)
{
rdataBytes = new Byte[rdlen];
Byte __pin * p = &rdataBytes[0];
memcpy(p, rdata, rdlen);
}
self->m_outer->QueryRecordDispatch((ServiceFlags) flags, (int) interfaceIndex, (ErrorCode) errorCode, ConvertToString(fullname), rrtype, rrclass, rdataBytes, ttl);
}
}
ServiceRef*
DNSService::EnumerateDomains
(
int flags,
int interfaceIndex,
EnumerateDomainsReply * callback
)
{
ServiceRef * sdRef = new ServiceRef(callback);
int err;
err = DNSServiceEnumerateDomains(&sdRef->m_impl->m_ref, flags, interfaceIndex, ServiceRef::ServiceRefImpl::EnumerateDomainsCallback, sdRef->m_impl);
if (err != 0)
{
throw new DNSServiceException(err);
}
sdRef->StartThread();
return sdRef;
}
ServiceRef*
DNSService::Register
(
int flags,
int interfaceIndex,
String * name,
String * regtype,
String * domain,
String * host,
int port,
Byte txtRecord[],
RegisterReply * callback
)
{
ServiceRef * sdRef = new ServiceRef(callback);
PString * pName = new PString(name);
PString * pType = new PString(regtype);
PString * pDomain = new PString(domain);
PString * pHost = new PString(host);
int len = 0;
Byte __pin * p = NULL;
void * v = NULL;
if ((txtRecord != NULL) && (txtRecord->Length > 0))
{
len = txtRecord->Length;
p = &txtRecord[0];
v = (void*) p;
}
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 );
if (err != 0)
{
throw new DNSServiceException(err);
}
sdRef->StartThread();
return sdRef;
}
RecordRef*
DNSService::AddRecord
(
ServiceRef * sdRef,
int flags,
int rrtype,
Byte rdata[],
int ttl
)
{
int len = 0;
Byte __pin * p = NULL;
void * v = NULL;
if ((rdata != NULL) && (rdata->Length > 0))
{
len = rdata->Length;
p = &rdata[0];
v = (void*) p;
}
RecordRef * record = new RecordRef;
int err = DNSServiceAddRecord(sdRef->m_impl->m_ref, &record->m_impl->m_ref, flags, rrtype, len, v, ttl);
if (err != 0)
{
throw new DNSServiceException(err);
}
return record;
}
void
DNSService::UpdateRecord
(
ServiceRef * sdRef,
RecordRef * record,
int flags,
Byte rdata[],
int ttl
)
{
int len = 0;
Byte __pin * p = NULL;
void * v = NULL;
if ((rdata != NULL) && (rdata->Length > 0))
{
len = rdata->Length;
p = &rdata[0];
v = (void*) p;
}
int err = DNSServiceUpdateRecord(sdRef->m_impl->m_ref, record ? record->m_impl->m_ref : NULL, flags, len, v, ttl);
if (err != 0)
{
throw new DNSServiceException(err);
}
}
void
DNSService::RemoveRecord
(
ServiceRef * sdRef,
RecordRef * record,
int flags
)
{
int err = DNSServiceRemoveRecord(sdRef->m_impl->m_ref, record->m_impl->m_ref, flags);
if (err != 0)
{
throw new DNSServiceException(err);
}
}
ServiceRef*
DNSService::Browse
(
int flags,
int interfaceIndex,
String * regtype,
String * domain,
BrowseReply * callback
)
{
ServiceRef * sdRef = new ServiceRef(callback);
PString * pType = new PString(regtype);
PString * pDomain = new PString(domain);
int err = DNSServiceBrowse(&sdRef->m_impl->m_ref, flags, interfaceIndex, pType->c_str(), pDomain->c_str(),(DNSServiceBrowseReply) ServiceRef::ServiceRefImpl::BrowseCallback, sdRef->m_impl);
if (err != 0)
{
throw new DNSServiceException(err);
}
sdRef->StartThread();
return sdRef;
}
ServiceRef*
DNSService::Resolve
(
int flags,
int interfaceIndex,
String * name,
String * regtype,
String * domain,
ResolveReply * callback
)
{
ServiceRef * sdRef = new ServiceRef(callback);
PString * pName = new PString(name);
PString * pType = new PString(regtype);
PString * pDomain = new PString(domain);
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);
if (err != 0)
{
throw new DNSServiceException(err);
}
sdRef->StartThread();
return sdRef;
}
ServiceRef*
DNSService::CreateConnection
(
RegisterRecordReply * callback
)
{
ServiceRef * sdRef = new ServiceRef(callback);
int err = DNSServiceCreateConnection(&sdRef->m_impl->m_ref);
if (err != 0)
{
throw new DNSServiceException(err);
}
sdRef->StartThread();
return sdRef;
}
RecordRef*
DNSService::RegisterRecord
(
ServiceRef * sdRef,
ServiceFlags flags,
int interfaceIndex,
String * fullname,
int rrtype,
int rrclass,
Byte rdata[],
int ttl
)
{
RecordRef * record = new RecordRef;
int len = 0;
Byte __pin * p = NULL;
void * v = NULL;
PString * pFullname = new PString(fullname);
if ((rdata != NULL) && (rdata->Length > 0))
{
len = rdata->Length;
p = &rdata[0];
v = (void*) p;
}
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);
if (err != 0)
{
throw new DNSServiceException(err);
}
return record;
}
ServiceRef*
DNSService::QueryRecord
(
ServiceFlags flags,
int interfaceIndex,
String * fullname,
int rrtype,
int rrclass,
QueryRecordReply * callback
)
{
ServiceRef * sdRef = new ServiceRef(callback);
PString * pFullname = new PString(fullname);
int err = DNSServiceQueryRecord(&sdRef->m_impl->m_ref, flags, interfaceIndex, pFullname->c_str(), rrtype, rrclass, (DNSServiceQueryRecordReply) ServiceRef::ServiceRefImpl::QueryRecordCallback, sdRef->m_impl);
if (err != 0)
{
throw new DNSServiceException(err);
}
sdRef->StartThread();
return sdRef;
}
void
DNSService::ReconfirmRecord
(
ServiceFlags flags,
int interfaceIndex,
String * fullname,
int rrtype,
int rrclass,
Byte rdata[]
)
{
int len = 0;
Byte __pin * p = NULL;
void * v = NULL;
PString * pFullname = new PString(fullname);
if ((rdata != NULL) && (rdata->Length > 0))
{
len = rdata->Length;
p = &rdata[0];
v = (void*) p;
}
DNSServiceReconfirmRecord(flags, interfaceIndex, pFullname->c_str(), rrtype, rrclass, len, v);
}
void
TextRecord::SetValue
(
String * key,
Byte value[]
)
{
PString * pKey = new PString(key);
int len = 0;
Byte __pin * p = NULL;
void * v = NULL;
DNSServiceErrorType err;
if (value && (value->Length > 0))
{
len = value->Length;
p = &value[0];
v = (void*) p;
}
err = TXTRecordSetValue(&m_impl->m_ref, pKey->c_str(), len, v);
if (err != 0)
{
throw new DNSServiceException(err);
}
}
void
TextRecord::RemoveValue
(
String * key
)
{
PString * pKey = new PString(key);
DNSServiceErrorType err;
err = TXTRecordRemoveValue(&m_impl->m_ref, pKey->c_str());
if (err != 0)
{
throw new DNSServiceException(err);
}
}
int
TextRecord::GetLength
(
)
{
return TXTRecordGetLength(&m_impl->m_ref);
}
Byte
TextRecord::GetBytes
(
) __gc[]
{
const void * noGCBytes = NULL;
Byte gcBytes[] = NULL;
noGCBytes = TXTRecordGetBytesPtr(&m_impl->m_ref);
int len = GetLength();
if (noGCBytes && len)
{
gcBytes = new Byte[len];
Byte __pin * p = &gcBytes[0];
memcpy(p, noGCBytes, len);
}
return gcBytes;
}
bool
TextRecord::ContainsKey
(
Byte txtRecord[],
String * key
)
{
PString * pKey = new PString(key);
Byte __pin * p = &txtRecord[0];
return (TXTRecordContainsKey(txtRecord->Length, p, pKey->c_str()) > 0) ? true : false;
}
Byte
TextRecord::GetValueBytes
(
Byte txtRecord[],
String * key
) __gc[]
{
uint8_t valueLen;
Byte ret[] = NULL;
PString * pKey = new PString(key);
Byte __pin * p1 = &txtRecord[0];
const void * v;
v = TXTRecordGetValuePtr(txtRecord->Length, p1, pKey->c_str(), &valueLen);
if (v != NULL)
{
ret = new Byte[valueLen];
Byte __pin * p2 = &ret[0];
memcpy(p2, v, valueLen);
}
return ret;
}
int
TextRecord::GetCount
(
Byte txtRecord[]
)
{
Byte __pin * p = &txtRecord[0];
return TXTRecordGetCount(txtRecord->Length, p);
}
Byte
TextRecord::GetItemAtIndex
(
Byte txtRecord[],
int index,
[Out] String ** key
) __gc[]
{
char keyBuf[255];
uint8_t keyBufLen = 255;
uint8_t valueLen;
void * value;
Byte ret[] = NULL;
DNSServiceErrorType err;
Byte __pin * p1 = &txtRecord[0];
err = TXTRecordGetItemAtIndex(txtRecord->Length, p1, index, keyBufLen, keyBuf, &valueLen, (const void**) &value);
if (err != 0)
{
throw new DNSServiceException(err);
}
*key = ConvertToString(keyBuf);
if (valueLen)
{
ret = new Byte[valueLen];
Byte __pin * p2 = &ret[0];
memcpy(p2, value, valueLen);
}
return ret;
}
DNSServiceException::DNSServiceException
(
int _err
)
:
err(_err)
{
}
DNSServiceException::DNSServiceException
(
String * message,
System::Exception * innerException
)
{
}