mirror of
https://git.rtems.org/rtems-libbsd/
synced 2025-06-14 01:27:34 +08:00

The sources can be obtained via: http://opensource.apple.com/tarballs/mDNSResponder/mDNSResponder-544.tar.gz
395 lines
7.6 KiB
C++
Executable File
395 lines
7.6 KiB
C++
Executable File
/* -*- 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() ) );
|
|
}
|
|
}
|
|
}
|
|
|