]> git.saurik.com Git - apple/mdnsresponder.git/blobdiff - Clients/FirefoxExtension/CDNSSDService.cpp
mDNSResponder-258.13.tar.gz
[apple/mdnsresponder.git] / Clients / FirefoxExtension / CDNSSDService.cpp
diff --git a/Clients/FirefoxExtension/CDNSSDService.cpp b/Clients/FirefoxExtension/CDNSSDService.cpp
new file mode 100755 (executable)
index 0000000..ae57da9
--- /dev/null
@@ -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() ) );
+               }
+       }
+}
+