1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 // This is the main DLL file.
22 #include "dnssd_NET.h"
23 #include "DebugServices.h"
27 using namespace System::Net::Sockets
;
28 using namespace System::Diagnostics
;
29 using namespace Apple
;
30 using namespace Apple::DNSSD
;
33 //===========================================================================================================================
35 //===========================================================================================================================
37 #define DEBUG_NAME "[dnssd.NET] "
43 ConvertToString(const char * utf8String
)
45 return __gc
new String(utf8String
, 0, strlen(utf8String
), __gc
new UTF8Encoding(true, true));
52 // ServiceRef serves as the base class for all DNSService operations.
54 // It manages the DNSServiceRef, and implements processing the
57 ServiceRef::ServiceRef(Object
* callback
)
63 m_impl
= new ServiceRefImpl(this);
67 ServiceRef::~ServiceRef()
75 // Starts the main processing thread
78 ServiceRef::StartThread()
80 check( m_impl
!= NULL
);
82 m_impl
->SetupEvents();
84 m_thread
= new Thread(new ThreadStart(this, &Apple::DNSSD::ServiceRef::ProcessingThread
));
85 m_thread
->Name
= S
"DNSService Thread";
86 m_thread
->IsBackground
= true;
95 // The Thread class can only invoke methods in MC++ types. So we
96 // make a ProcessingThread method that forwards to the impl
99 ServiceRef::ProcessingThread()
101 m_impl
->ProcessingThread();
108 // Calls impl-Dispose(). This ultimately will call DNSServiceRefDeallocate()
111 ServiceRef::Dispose()
113 check(m_impl
!= NULL
);
114 check(m_bDisposed
== false);
121 // Call Dispose. This won't call DNSServiceRefDeallocate()
122 // necessarily. It depends on what thread this is being
130 GC::SuppressFinalize(this);
136 // EnumerateDomainsDispatch
138 // Dispatch a reply to the delegate.
141 ServiceRef::EnumerateDomainsDispatch
149 if ((m_callback
!= NULL
) && (m_impl
!= NULL
))
151 DNSService::EnumerateDomainsReply
* OnEnumerateDomainsReply
= static_cast<DNSService::EnumerateDomainsReply
*>(m_callback
);
152 OnEnumerateDomainsReply(this, flags
, interfaceIndex
, errorCode
, replyDomain
);
160 // Dispatch a reply to the delegate.
163 ServiceRef::RegisterDispatch
172 if ((m_callback
!= NULL
) && (m_impl
!= NULL
))
174 DNSService::RegisterReply
* OnRegisterReply
= static_cast<DNSService::RegisterReply
*>(m_callback
);
175 OnRegisterReply(this, flags
, errorCode
, name
, regtype
, domain
);
183 // Dispatch a reply to the delegate.
186 ServiceRef::BrowseDispatch
191 String
* serviceName
,
196 if ((m_callback
!= NULL
) && (m_impl
!= NULL
))
198 DNSService::BrowseReply
* OnBrowseReply
= static_cast<DNSService::BrowseReply
*>(m_callback
);
199 OnBrowseReply(this, flags
, interfaceIndex
, errorCode
, serviceName
, regtype
, replyDomain
);
207 // Dispatch a reply to the delegate.
210 ServiceRef::ResolveDispatch
221 if ((m_callback
!= NULL
) && (m_impl
!= NULL
))
223 DNSService::ResolveReply
* OnResolveReply
= static_cast<DNSService::ResolveReply
*>(m_callback
);
224 OnResolveReply(this, flags
, interfaceIndex
, errorCode
, fullname
, hosttarget
, port
, txtRecord
);
230 // RegisterRecordDispatch
232 // Dispatch a reply to the delegate.
235 ServiceRef::RegisterRecordDispatch
242 if ((m_callback
!= NULL
) && (m_impl
!= NULL
))
244 DNSService::RegisterRecordReply
* OnRegisterRecordReply
= static_cast<DNSService::RegisterRecordReply
*>(m_callback
);
245 OnRegisterRecordReply(this, flags
, errorCode
, record
);
251 // QueryRecordDispatch
253 // Dispatch a reply to the delegate.
256 ServiceRef::QueryRecordDispatch
268 if ((m_callback
!= NULL
) && (m_impl
!= NULL
))
270 DNSService::QueryRecordReply
* OnQueryRecordReply
= static_cast<DNSService::QueryRecordReply
*>(m_callback
);
271 OnQueryRecordReply(this, flags
, interfaceIndex
, errorCode
, fullname
, rrtype
, rrclass
, rdata
, ttl
);
277 // ServiceRefImpl::ServiceRefImpl()
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
283 ServiceRef::ServiceRefImpl::ServiceRefImpl(ServiceRef
* outer
)
291 m_threadId
= GetCurrentThreadId();
296 // ServiceRefImpl::~ServiceRefImpl()
298 // Deallocate all resources associated with the ServiceRefImpl
300 ServiceRef::ServiceRefImpl::~ServiceRefImpl()
302 if (m_socketEvent
!= NULL
)
304 CloseHandle(m_socketEvent
);
305 m_socketEvent
= NULL
;
308 if (m_stopEvent
!= NULL
)
310 CloseHandle(m_stopEvent
);
316 DNSServiceRefDeallocate(m_ref
);
323 // ServiceRefImpl::SetupEvents()
325 // Setup the events necessary to manage multi-threaded dispatch
326 // of DNSService Events
329 ServiceRef::ServiceRefImpl::SetupEvents()
331 check(m_ref
!= NULL
);
333 m_socket
= (SOCKET
) DNSServiceRefSockFD(m_ref
);
334 check(m_socket
!= INVALID_SOCKET
);
336 m_socketEvent
= CreateEvent(NULL
, 0, 0, NULL
);
338 if (m_socketEvent
== NULL
)
340 throw new DNSServiceException(Unknown
);
343 int err
= WSAEventSelect(m_socket
, m_socketEvent
, FD_READ
|FD_CLOSE
);
347 throw new DNSServiceException(Unknown
);
350 m_stopEvent
= CreateEvent(NULL
, 0, 0, NULL
);
352 if (m_stopEvent
== NULL
)
354 throw new DNSServiceException(Unknown
);
360 // ServiceRefImpl::ProcessingThread()
362 // Wait for socket events on the DNSServiceRefSockFD(). Also wait
366 ServiceRef::ServiceRefImpl::ProcessingThread()
368 check( m_socketEvent
!= NULL
);
369 check( m_stopEvent
!= NULL
);
370 check( m_ref
!= NULL
);
374 handles
[0] = m_socketEvent
;
375 handles
[1] = m_stopEvent
;
377 while (m_disposed
== false)
379 int ret
= WaitForMultipleObjects(2, handles
, FALSE
, INFINITE
);
382 // it's a socket event
384 if (ret
== WAIT_OBJECT_0
)
386 DNSServiceProcessResult(m_ref
);
389 // else it's a stop event
391 else if (ret
== WAIT_OBJECT_0
+ 1)
398 // unexpected wait result
400 dlog( kDebugLevelWarning
, DEBUG_NAME
"%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__
, ret
);
409 // ServiceRefImpl::Dispose()
411 // Calls DNSServiceRefDeallocate()
414 ServiceRef::ServiceRefImpl::Dispose()
419 check(m_disposed
== false);
423 ok
= SetEvent(m_stopEvent
);
424 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
425 require_noerr( err
, exit
);
434 // ServiceRefImpl::EnumerateDomainsCallback()
436 // This is the callback from dnssd.dll. We pass this up to our outer, managed type
439 ServiceRef::ServiceRefImpl::EnumerateDomainsCallback
442 DNSServiceFlags flags
,
443 uint32_t interfaceIndex
,
444 DNSServiceErrorType errorCode
,
445 const char * replyDomain
,
449 ServiceRef::ServiceRefImpl
* self
= static_cast<ServiceRef::ServiceRefImpl
*>(context
);
451 check( self
!= NULL
);
452 check( self
->m_outer
!= NULL
);
454 if (self
->m_disposed
== false)
456 self
->m_outer
->EnumerateDomainsDispatch((ServiceFlags
) flags
, interfaceIndex
, (ErrorCode
) errorCode
, ConvertToString(replyDomain
));
462 // ServiceRefImpl::RegisterCallback()
464 // This is the callback from dnssd.dll. We pass this up to our outer, managed type
467 ServiceRef::ServiceRefImpl::RegisterCallback
470 DNSServiceFlags flags
,
471 DNSServiceErrorType errorCode
,
473 const char * regtype
,
478 ServiceRef::ServiceRefImpl
* self
= static_cast<ServiceRef::ServiceRefImpl
*>(context
);
480 check( self
!= NULL
);
481 check( self
->m_outer
!= NULL
);
483 if (self
->m_disposed
== false)
485 self
->m_outer
->RegisterDispatch((ServiceFlags
) flags
, (ErrorCode
) errorCode
, ConvertToString(name
), ConvertToString(regtype
), ConvertToString(domain
));
491 // ServiceRefImpl::BrowseCallback()
493 // This is the callback from dnssd.dll. We pass this up to our outer, managed type
496 ServiceRef::ServiceRefImpl::BrowseCallback
499 DNSServiceFlags flags
,
500 uint32_t interfaceIndex
,
501 DNSServiceErrorType errorCode
,
502 const char * serviceName
,
503 const char * regtype
,
504 const char * replyDomain
,
508 ServiceRef::ServiceRefImpl
* self
= static_cast<ServiceRef::ServiceRefImpl
*>(context
);
510 check( self
!= NULL
);
511 check( self
->m_outer
!= NULL
);
513 if (self
->m_disposed
== false)
515 self
->m_outer
->BrowseDispatch((ServiceFlags
) flags
, interfaceIndex
, (ErrorCode
) errorCode
, ConvertToString(serviceName
), ConvertToString(regtype
), ConvertToString(replyDomain
));
521 // ServiceRefImpl::ResolveCallback()
523 // This is the callback from dnssd.dll. We pass this up to our outer, managed type
526 ServiceRef::ServiceRefImpl::ResolveCallback
529 DNSServiceFlags flags
,
530 uint32_t interfaceIndex
,
531 DNSServiceErrorType errorCode
,
532 const char * fullname
,
533 const char * hosttarget
,
534 uint16_t notAnIntPort
,
536 const char * txtRecord
,
540 ServiceRef::ServiceRefImpl
* self
= static_cast<ServiceRef::ServiceRefImpl
*>(context
);
542 check( self
!= NULL
);
543 check( self
->m_outer
!= NULL
);
545 if (self
->m_disposed
== false)
547 Byte txtRecordBytes
[];
549 txtRecordBytes
= NULL
;
554 // copy raw memory into managed byte array
556 txtRecordBytes
= new Byte
[txtLen
];
557 Byte __pin
* p
= &txtRecordBytes
[0];
558 memcpy(p
, txtRecord
, txtLen
);
561 self
->m_outer
->ResolveDispatch((ServiceFlags
) flags
, interfaceIndex
, (ErrorCode
) errorCode
, ConvertToString(fullname
), ConvertToString(hosttarget
), ntohs(notAnIntPort
), txtRecordBytes
);
567 // ServiceRefImpl::RegisterRecordCallback()
569 // This is the callback from dnssd.dll. We pass this up to our outer, managed type
572 ServiceRef::ServiceRefImpl::RegisterRecordCallback
576 DNSServiceFlags flags
,
577 DNSServiceErrorType errorCode
,
581 ServiceRef::ServiceRefImpl
* self
= static_cast<ServiceRef::ServiceRefImpl
*>(context
);
583 check( self
!= NULL
);
584 check( self
->m_outer
!= NULL
);
586 if (self
->m_disposed
== false)
588 RecordRef
* record
= NULL
;
592 record
= new RecordRef
;
594 record
->m_impl
->m_ref
= rrRef
;
597 self
->m_outer
->RegisterRecordDispatch((ServiceFlags
) flags
, (ErrorCode
) errorCode
, record
);
603 // ServiceRefImpl::QueryRecordCallback()
605 // This is the callback from dnssd.dll. We pass this up to our outer, managed type
608 ServiceRef::ServiceRefImpl::QueryRecordCallback
610 DNSServiceRef DNSServiceRef
,
611 DNSServiceFlags flags
,
612 uint32_t interfaceIndex
,
613 DNSServiceErrorType errorCode
,
614 const char * fullname
,
623 ServiceRef::ServiceRefImpl
* self
= static_cast<ServiceRef::ServiceRefImpl
*>(context
);
625 check( self
!= NULL
);
626 check( self
->m_outer
!= NULL
);
628 if (self
->m_disposed
== false)
634 rdataBytes
= new Byte
[rdlen
];
635 Byte __pin
* p
= &rdataBytes
[0];
636 memcpy(p
, rdata
, rdlen
);
639 self
->m_outer
->QueryRecordDispatch((ServiceFlags
) flags
, (int) interfaceIndex
, (ErrorCode
) errorCode
, ConvertToString(fullname
), rrtype
, rrclass
, rdataBytes
, ttl
);
647 * This maps to DNSServiceEnumerateDomains(). Returns an
648 * initialized ServiceRef on success, throws an exception
652 DNSService::EnumerateDomains
656 EnumerateDomainsReply
* callback
659 ServiceRef
* sdRef
= new ServiceRef(callback
);
662 err
= DNSServiceEnumerateDomains(&sdRef
->m_impl
->m_ref
, flags
, interfaceIndex
, ServiceRef::ServiceRefImpl::EnumerateDomainsCallback
, sdRef
->m_impl
);
666 throw new DNSServiceException(err
);
669 sdRef
->StartThread();
678 * This maps to DNSServiceRegister(). Returns an
679 * initialized ServiceRef on success, throws an exception
693 RegisterReply
* callback
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
);
702 Byte __pin
* p
= NULL
;
705 if ((txtRecord
!= NULL
) && (txtRecord
->Length
> 0))
707 len
= txtRecord
->Length
;
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
);
716 throw new DNSServiceException(err
);
719 sdRef
->StartThread();
728 * This maps to DNSServiceAddRecord(). Returns an
729 * initialized ServiceRef on success, throws an exception
733 DNSService::AddRecord
743 Byte __pin
* p
= NULL
;
746 if ((rdata
!= NULL
) && (rdata
->Length
> 0))
753 RecordRef
* record
= new RecordRef
;
755 int err
= DNSServiceAddRecord(sdRef
->m_impl
->m_ref
, &record
->m_impl
->m_ref
, flags
, rrtype
, len
, v
, ttl
);
759 throw new DNSServiceException(err
);
769 * This maps to DNSServiceUpdateRecord(). Returns an
770 * initialized ServiceRef on success, throws an exception
774 DNSService::UpdateRecord
784 Byte __pin
* p
= NULL
;
787 if ((rdata
!= NULL
) && (rdata
->Length
> 0))
794 int err
= DNSServiceUpdateRecord(sdRef
->m_impl
->m_ref
, record
? record
->m_impl
->m_ref
: NULL
, flags
, len
, v
, ttl
);
798 throw new DNSServiceException(err
);
806 * This maps to DNSServiceRemoveRecord(). Returns an
807 * initialized ServiceRef on success, throws an exception
811 DNSService::RemoveRecord
818 int err
= DNSServiceRemoveRecord(sdRef
->m_impl
->m_ref
, record
->m_impl
->m_ref
, flags
);
822 throw new DNSServiceException(err
);
830 * This maps to DNSServiceBrowse(). Returns an
831 * initialized ServiceRef on success, throws an exception
841 BrowseReply
* callback
844 ServiceRef
* sdRef
= new ServiceRef(callback
);
845 PString
* pType
= new PString(regtype
);
846 PString
* pDomain
= new PString(domain
);
848 int err
= DNSServiceBrowse(&sdRef
->m_impl
->m_ref
, flags
, interfaceIndex
, pType
->c_str(), pDomain
->c_str(),(DNSServiceBrowseReply
) ServiceRef::ServiceRefImpl::BrowseCallback
, sdRef
->m_impl
);
852 throw new DNSServiceException(err
);
855 sdRef
->StartThread();
864 * This maps to DNSServiceResolve(). Returns an
865 * initialized ServiceRef on success, throws an exception
876 ResolveReply
* callback
879 ServiceRef
* sdRef
= new ServiceRef(callback
);
880 PString
* pName
= new PString(name
);
881 PString
* pType
= new PString(regtype
);
882 PString
* pDomain
= new PString(domain
);
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
);
888 throw new DNSServiceException(err
);
891 sdRef
->StartThread();
900 * This maps to DNSServiceCreateConnection(). Returns an
901 * initialized ServiceRef on success, throws an exception
905 DNSService::CreateConnection
907 RegisterRecordReply
* callback
910 ServiceRef
* sdRef
= new ServiceRef(callback
);
912 int err
= DNSServiceCreateConnection(&sdRef
->m_impl
->m_ref
);
916 throw new DNSServiceException(err
);
919 sdRef
->StartThread();
928 * This maps to DNSServiceRegisterRecord(). Returns an
929 * initialized ServiceRef on success, throws an exception
934 DNSService::RegisterRecord
946 RecordRef
* record
= new RecordRef
;
948 Byte __pin
* p
= NULL
;
951 PString
* pFullname
= new PString(fullname
);
953 if ((rdata
!= NULL
) && (rdata
->Length
> 0))
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
);
964 throw new DNSServiceException(err
);
973 * This maps to DNSServiceQueryRecord(). Returns an
974 * initialized ServiceRef on success, throws an exception
978 DNSService::QueryRecord
985 QueryRecordReply
* callback
988 ServiceRef
* sdRef
= new ServiceRef(callback
);
989 PString
* pFullname
= new PString(fullname
);
991 int err
= DNSServiceQueryRecord(&sdRef
->m_impl
->m_ref
, flags
, interfaceIndex
, pFullname
->c_str(), rrtype
, rrclass
, (DNSServiceQueryRecordReply
) ServiceRef::ServiceRefImpl::QueryRecordCallback
, sdRef
->m_impl
);
995 throw new DNSServiceException(err
);
998 sdRef
->StartThread();
1007 * This maps to DNSServiceReconfirmRecord(). Returns an
1008 * initialized ServiceRef on success, throws an exception
1012 DNSService::ReconfirmRecord
1023 Byte __pin
* p
= NULL
;
1026 PString
* pFullname
= new PString(fullname
);
1028 if ((rdata
!= NULL
) && (rdata
->Length
> 0))
1030 len
= rdata
->Length
;
1035 DNSServiceReconfirmRecord(flags
, interfaceIndex
, pFullname
->c_str(), rrtype
, rrclass
, len
, v
);
1040 TextRecord::SetValue
1043 Byte value
[] /* may be NULL */
1046 PString
* pKey
= new PString(key
);
1048 Byte __pin
* p
= NULL
;
1050 DNSServiceErrorType err
;
1052 if (value
&& (value
->Length
> 0))
1054 len
= value
->Length
;
1059 err
= TXTRecordSetValue(&m_impl
->m_ref
, pKey
->c_str(), len
, v
);
1063 throw new DNSServiceException(err
);
1069 TextRecord::RemoveValue
1074 PString
* pKey
= new PString(key
);
1075 DNSServiceErrorType err
;
1077 err
= TXTRecordRemoveValue(&m_impl
->m_ref
, pKey
->c_str());
1081 throw new DNSServiceException(err
);
1087 TextRecord::GetLength
1091 return TXTRecordGetLength(&m_impl
->m_ref
);
1096 TextRecord::GetBytes
1100 const void * noGCBytes
= NULL
;
1101 Byte gcBytes
[] = NULL
;
1103 noGCBytes
= TXTRecordGetBytesPtr(&m_impl
->m_ref
);
1104 int len
= GetLength();
1106 if (noGCBytes
&& len
)
1108 gcBytes
= new Byte
[len
];
1109 Byte __pin
* p
= &gcBytes
[0];
1110 memcpy(p
, noGCBytes
, len
);
1118 TextRecord::ContainsKey
1124 PString
* pKey
= new PString(key
);
1125 Byte __pin
* p
= &txtRecord
[0];
1127 return (TXTRecordContainsKey(txtRecord
->Length
, p
, pKey
->c_str()) > 0) ? true : false;
1132 TextRecord::GetValueBytes
1140 PString
* pKey
= new PString(key
);
1141 Byte __pin
* p1
= &txtRecord
[0];
1144 v
= TXTRecordGetValuePtr(txtRecord
->Length
, p1
, pKey
->c_str(), &valueLen
);
1148 ret
= new Byte
[valueLen
];
1149 Byte __pin
* p2
= &ret
[0];
1151 memcpy(p2
, v
, valueLen
);
1159 TextRecord::GetCount
1164 Byte __pin
* p
= &txtRecord
[0];
1166 return TXTRecordGetCount(txtRecord
->Length
, p
);
1171 TextRecord::GetItemAtIndex
1179 uint8_t keyBufLen
= 255;
1183 DNSServiceErrorType err
;
1184 Byte __pin
* p1
= &txtRecord
[0];
1187 err
= TXTRecordGetItemAtIndex(txtRecord
->Length
, p1
, index
, keyBufLen
, keyBuf
, &valueLen
, (const void**) &value
);
1191 throw new DNSServiceException(err
);
1194 *key
= ConvertToString(keyBuf
);
1198 ret
= new Byte
[valueLen
];
1199 Byte __pin
* p2
= &ret
[0];
1201 memcpy(p2
, value
, valueLen
);
1209 // DNSServiceException::DNSServiceException()
1211 // Constructs an exception with an error code
1213 DNSServiceException::DNSServiceException
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
1228 DNSServiceException::DNSServiceException
1231 System::Exception
* innerException