diff options
Diffstat (limited to 'mDNSResponder/Clients/FirefoxExtension/CDNSSDService.cpp')
-rwxr-xr-x | mDNSResponder/Clients/FirefoxExtension/CDNSSDService.cpp | 394 |
1 files changed, 394 insertions, 0 deletions
diff --git a/mDNSResponder/Clients/FirefoxExtension/CDNSSDService.cpp b/mDNSResponder/Clients/FirefoxExtension/CDNSSDService.cpp new file mode 100755 index 00000000..ae57da94 --- /dev/null +++ b/mDNSResponder/Clients/FirefoxExtension/CDNSSDService.cpp @@ -0,0 +1,394 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2009 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. + */ + +#include "CDNSSDService.h" +#include "nsThreadUtils.h" +#include "nsIEventTarget.h" +#include "private/pprio.h" +#include <string> +#include <stdio.h> + + +NS_IMPL_ISUPPORTS2(CDNSSDService, IDNSSDService, nsIRunnable) + +CDNSSDService::CDNSSDService() +: + m_master( 1 ), + m_threadPool( NULL ), + m_mainRef( NULL ), + m_subRef( NULL ), + m_listener( NULL ), + m_fileDesc( NULL ), + m_job( NULL ) +{ + nsresult err; + + if ( DNSServiceCreateConnection( &m_mainRef ) != kDNSServiceErr_NoError ) + { + err = NS_ERROR_FAILURE; + goto exit; + } + + if ( ( m_fileDesc = PR_ImportTCPSocket( DNSServiceRefSockFD( m_mainRef ) ) ) == NULL ) + { + err = NS_ERROR_FAILURE; + goto exit; + } + + if ( ( m_threadPool = PR_CreateThreadPool( 1, 1, 8192 ) ) == NULL ) + { + err = NS_ERROR_FAILURE; + goto exit; + } + + err = SetupNotifications(); + +exit: + + if ( err != NS_OK ) + { + Cleanup(); + } +} + + +CDNSSDService::CDNSSDService( DNSServiceRef ref, nsISupports * listener ) +: + m_master( 0 ), + m_threadPool( NULL ), + m_mainRef( ref ), + m_subRef( ref ), + m_listener( listener ), + m_fileDesc( NULL ), + m_job( NULL ) +{ +} + + +CDNSSDService::~CDNSSDService() +{ + Cleanup(); +} + + +void +CDNSSDService::Cleanup() +{ + if ( m_master ) + { + if ( m_job ) + { + PR_CancelJob( m_job ); + m_job = NULL; + } + + if ( m_threadPool != NULL ) + { + PR_ShutdownThreadPool( m_threadPool ); + m_threadPool = NULL; + } + + if ( m_fileDesc != NULL ) + { + PR_Close( m_fileDesc ); + m_fileDesc = NULL; + } + + if ( m_mainRef ) + { + DNSServiceRefDeallocate( m_mainRef ); + m_mainRef = NULL; + } + } + else + { + if ( m_subRef ) + { + DNSServiceRefDeallocate( m_subRef ); + m_subRef = NULL; + } + } +} + + +nsresult +CDNSSDService::SetupNotifications() +{ + NS_PRECONDITION( m_threadPool != NULL, "m_threadPool is NULL" ); + NS_PRECONDITION( m_fileDesc != NULL, "m_fileDesc is NULL" ); + NS_PRECONDITION( m_job == NULL, "m_job is not NULL" ); + + m_iod.socket = m_fileDesc; + m_iod.timeout = PR_INTERVAL_MAX; + m_job = PR_QueueJob_Read( m_threadPool, &m_iod, Read, this, PR_FALSE ); + return ( m_job ) ? NS_OK : NS_ERROR_FAILURE; +} + + +/* IDNSSDService browse (in long interfaceIndex, in AString regtype, in AString domain, in IDNSSDBrowseListener listener); */ +NS_IMETHODIMP +CDNSSDService::Browse(PRInt32 interfaceIndex, const nsAString & regtype, const nsAString & domain, IDNSSDBrowseListener *listener, IDNSSDService **_retval NS_OUTPARAM) +{ + CDNSSDService * service = NULL; + DNSServiceErrorType dnsErr = 0; + nsresult err = 0; + + *_retval = NULL; + + if ( !m_mainRef ) + { + err = NS_ERROR_NOT_AVAILABLE; + goto exit; + } + + try + { + service = new CDNSSDService( m_mainRef, listener ); + } + catch ( ... ) + { + service = NULL; + } + + if ( service == NULL ) + { + err = NS_ERROR_FAILURE; + goto exit; + } + + dnsErr = DNSServiceBrowse( &service->m_subRef, kDNSServiceFlagsShareConnection, interfaceIndex, NS_ConvertUTF16toUTF8( regtype ).get(), NS_ConvertUTF16toUTF8( domain ).get(), ( DNSServiceBrowseReply ) BrowseReply, service ); + + if ( dnsErr != kDNSServiceErr_NoError ) + { + err = NS_ERROR_FAILURE; + goto exit; + } + + listener->AddRef(); + service->AddRef(); + *_retval = service; + err = NS_OK; + +exit: + + if ( err && service ) + { + delete service; + service = NULL; + } + + return err; +} + + +/* IDNSSDService resolve (in long interfaceIndex, in AString name, in AString regtype, in AString domain, in IDNSSDResolveListener listener); */ +NS_IMETHODIMP +CDNSSDService::Resolve(PRInt32 interfaceIndex, const nsAString & name, const nsAString & regtype, const nsAString & domain, IDNSSDResolveListener *listener, IDNSSDService **_retval NS_OUTPARAM) +{ + CDNSSDService * service; + DNSServiceErrorType dnsErr; + nsresult err; + + *_retval = NULL; + + if ( !m_mainRef ) + { + err = NS_ERROR_NOT_AVAILABLE; + goto exit; + } + + try + { + service = new CDNSSDService( m_mainRef, listener ); + } + catch ( ... ) + { + service = NULL; + } + + if ( service == NULL ) + { + err = NS_ERROR_FAILURE; + goto exit; + } + + dnsErr = DNSServiceResolve( &service->m_subRef, kDNSServiceFlagsShareConnection, interfaceIndex, NS_ConvertUTF16toUTF8( name ).get(), NS_ConvertUTF16toUTF8( regtype ).get(), NS_ConvertUTF16toUTF8( domain ).get(), ( DNSServiceResolveReply ) ResolveReply, service ); + + if ( dnsErr != kDNSServiceErr_NoError ) + { + err = NS_ERROR_FAILURE; + goto exit; + } + + listener->AddRef(); + service->AddRef(); + *_retval = service; + err = NS_OK; + +exit: + + if ( err && service ) + { + delete service; + service = NULL; + } + + return err; +} + + +/* void stop (); */ +NS_IMETHODIMP +CDNSSDService::Stop() +{ + if ( m_subRef ) + { + DNSServiceRefDeallocate( m_subRef ); + m_subRef = NULL; + } + + return NS_OK; +} + + +void +CDNSSDService::Read( void * arg ) +{ + NS_PRECONDITION( arg != NULL, "arg is NULL" ); + + NS_DispatchToMainThread( ( CDNSSDService* ) arg ); +} + + +NS_IMETHODIMP +CDNSSDService::Run() +{ + nsresult err = NS_OK; + + NS_PRECONDITION( m_mainRef != NULL, "m_mainRef is NULL" ); + + m_job = NULL; + + if ( PR_Available( m_fileDesc ) > 0 ) + { + if ( DNSServiceProcessResult( m_mainRef ) != kDNSServiceErr_NoError ) + { + err = NS_ERROR_FAILURE; + } + } + + if ( !err ) + { + err = SetupNotifications(); + } + + return err; +} + + +void DNSSD_API +CDNSSDService::BrowseReply + ( + DNSServiceRef sdRef, + DNSServiceFlags flags, + uint32_t interfaceIndex, + DNSServiceErrorType errorCode, + const char * serviceName, + const char * regtype, + const char * replyDomain, + void * context + ) +{ + CDNSSDService * self = ( CDNSSDService* ) context; + + // This should never be NULL, but let's be defensive. + + if ( self != NULL ) + { + IDNSSDBrowseListener * listener = ( IDNSSDBrowseListener* ) self->m_listener; + + // Same for this + + if ( listener != NULL ) + { + listener->OnBrowse( self, ( flags & kDNSServiceFlagsAdd ) ? PR_TRUE : PR_FALSE, interfaceIndex, errorCode, NS_ConvertUTF8toUTF16( serviceName ), NS_ConvertUTF8toUTF16( regtype ), NS_ConvertUTF8toUTF16( replyDomain ) ); + } + } +} + + +void DNSSD_API +CDNSSDService::ResolveReply + ( + DNSServiceRef sdRef, + DNSServiceFlags flags, + uint32_t interfaceIndex, + DNSServiceErrorType errorCode, + const char * fullname, + const char * hosttarget, + uint16_t port, + uint16_t txtLen, + const unsigned char * txtRecord, + void * context + ) +{ + CDNSSDService * self = ( CDNSSDService* ) context; + + // This should never be NULL, but let's be defensive. + + if ( self != NULL ) + { + IDNSSDResolveListener * listener = ( IDNSSDResolveListener* ) self->m_listener; + + // Same for this + + if ( listener != NULL ) + { + std::string path = ""; + const void * value = NULL; + uint8_t valueLen = 0; + + value = TXTRecordGetValuePtr( txtLen, txtRecord, "path", &valueLen ); + + if ( value && valueLen ) + { + char * temp; + + temp = new char[ valueLen + 2 ]; + + if ( temp ) + { + char * dst = temp; + + memset( temp, 0, valueLen + 2 ); + + if ( ( ( char* ) value )[ 0 ] != '/' ) + { + *dst++ = '/'; + } + + memcpy( dst, value, valueLen ); + path = temp; + delete [] temp; + } + } + + listener->OnResolve( self, interfaceIndex, errorCode, NS_ConvertUTF8toUTF16( fullname ), NS_ConvertUTF8toUTF16( hosttarget ) , ntohs( port ), NS_ConvertUTF8toUTF16( path.c_str() ) ); + } + } +} + |