<rdar://problem/3807636> Add Apache license verbiage to source code
[people/sha0/mDNSResponder.git] / Clients / FirefoxExtension / CDNSSDService.cpp
1 /* -*- Mode: C; tab-width: 4 -*-
2  *
3  * Copyright (c) 2009 Apple Computer, Inc. All rights reserved.
4  *
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
8  * 
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  * 
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.
16  */
17
18 #include "CDNSSDService.h"
19 #include "nsThreadUtils.h"
20 #include "nsIEventTarget.h"
21 #include "private/pprio.h"
22 #include <string>
23 #include <stdio.h>
24
25 static FILE * m_fp;
26
27
28 NS_IMPL_ISUPPORTS2(CDNSSDService, IDNSSDService, nsIRunnable)
29
30 CDNSSDService::CDNSSDService()
31 :
32         m_threadPool( NULL ),
33         m_mainRef( NULL ),
34         m_subRef( NULL ),
35         m_listener( NULL ),
36         m_fileDesc( NULL ),
37         m_job( NULL )
38 {
39         nsresult err;
40
41         //m_fp = fopen( "/Users/scott/scott.txt", "w+" );
42         m_fp = stderr;
43         fprintf( m_fp, "CDNSSDService::CDNSSDService( this = 0x%x )\n", this );
44         fflush( m_fp );
45         
46         if ( DNSServiceCreateConnection( &m_mainRef ) != kDNSServiceErr_NoError )
47         {
48                 err = NS_ERROR_FAILURE;
49                 goto exit;
50         }
51
52         if ( ( m_fileDesc = PR_ImportTCPSocket( DNSServiceRefSockFD( m_mainRef ) ) ) == NULL )
53         {
54                 err = NS_ERROR_FAILURE;
55                 goto exit;
56         }
57
58         if ( ( m_threadPool = PR_CreateThreadPool( 1, 1, 8192 ) ) == NULL )
59         {
60                 err = NS_ERROR_FAILURE;
61                 goto exit;
62         }
63         
64         err = SetupNotifications();
65
66 exit:
67
68         if ( err != NS_OK )
69         {
70                 Cleanup();
71         }
72 }
73
74
75 CDNSSDService::CDNSSDService( DNSServiceRef ref, nsISupports * listener )
76 :
77         m_threadPool( NULL ),
78         m_mainRef( ref ),
79         m_subRef( ref ),
80         m_listener( listener ),
81         m_fileDesc( NULL ),
82         m_job( NULL )
83 {
84 }
85
86
87 CDNSSDService::~CDNSSDService()
88 {
89         fprintf( m_fp, "in CDNSSDService::~CDNSSDService( this = 0x%x)\n", this );
90         fflush( m_fp );
91         
92         Cleanup();
93 }
94
95
96 void
97 CDNSSDService::Cleanup()
98 {
99         if ( m_job )
100         {
101                 PR_CancelJob( m_job );
102                 m_job = NULL;
103         }
104
105         if ( m_threadPool != NULL )
106         {
107                 PR_ShutdownThreadPool( m_threadPool );
108                 m_threadPool = NULL;
109         }
110         
111         if ( m_fileDesc != NULL )
112         {
113                 PR_Close( m_fileDesc );
114                 m_fileDesc = NULL;
115         }
116         
117         if ( m_subRef )
118         {
119                 DNSServiceRefDeallocate( m_subRef );
120                 m_subRef = NULL;
121         }
122         else if ( m_mainRef )
123         {
124                 DNSServiceRefDeallocate( m_mainRef );
125                 m_mainRef = NULL;
126         }
127 }
128
129
130 nsresult
131 CDNSSDService::SetupNotifications()
132 {
133         NS_PRECONDITION( m_threadPool != NULL, "m_threadPool is NULL" );
134         NS_PRECONDITION( m_fileDesc != NULL, "m_fileDesc is NULL" );
135         NS_PRECONDITION( m_job == NULL, "m_job is not NULL" );
136
137         m_iod.socket    = m_fileDesc;
138         m_iod.timeout   = PR_INTERVAL_MAX;
139         m_job                   = PR_QueueJob_Read( m_threadPool, &m_iod, Read, this, PR_FALSE );       
140         return ( m_job ) ? NS_OK : NS_ERROR_FAILURE;
141 }
142
143
144 /* IDNSSDService browse (in long interfaceIndex, in AString regtype, in AString domain, in IDNSSDBrowseListener listener); */
145 NS_IMETHODIMP
146 CDNSSDService::Browse(PRInt32 interfaceIndex, const nsAString & regtype, const nsAString & domain, IDNSSDBrowseListener *listener, IDNSSDService **_retval NS_OUTPARAM)
147 {
148         CDNSSDService   *       service = NULL;
149         DNSServiceErrorType dnsErr      = 0;
150         nsresult                        err             = 0;
151
152         *_retval = NULL;
153         
154         fprintf( m_fp, "in Browse( listener = 0x%x )\n", listener );
155         fflush( m_fp );
156         
157         if ( !m_mainRef )
158         {
159                 err = NS_ERROR_NOT_AVAILABLE;
160                 goto exit;
161         }
162
163         try
164         {
165                 service = new CDNSSDService( m_mainRef, listener );
166         }
167         catch ( ... )
168         {
169                 service = NULL;
170         }
171         
172         fprintf( m_fp, "created new service\n" );
173         fflush( m_fp );
174
175         if ( service == NULL )
176         {
177                 err = NS_ERROR_FAILURE;
178                 goto exit;
179         }
180         
181         dnsErr = DNSServiceBrowse( &service->m_subRef, kDNSServiceFlagsShareConnection, interfaceIndex, NS_ConvertUTF16toUTF8( regtype ).get(), NS_ConvertUTF16toUTF8( domain ).get(), ( DNSServiceBrowseReply ) BrowseReply, service );
182         
183         if ( dnsErr != kDNSServiceErr_NoError )
184         {
185                 fprintf( m_fp, "DNSServiceBrowse failed\n" );
186                 fflush( m_fp );
187                 err = NS_ERROR_FAILURE;
188                 goto exit;
189         }
190         
191         listener->AddRef();
192         service->AddRef();
193         *_retval = service;
194         err = NS_OK;
195         
196         fprintf( m_fp, "did DNSServiceBrowse\n" );
197         fflush( m_fp );
198         
199 exit:
200
201         if ( err && service )
202         {
203                 delete service;
204                 service = NULL;
205         }
206         
207         return err;
208 }
209
210
211 /* IDNSSDService resolve (in long interfaceIndex, in AString name, in AString regtype, in AString domain, in IDNSSDResolveListener listener); */
212 NS_IMETHODIMP
213 CDNSSDService::Resolve(PRInt32 interfaceIndex, const nsAString & name, const nsAString & regtype, const nsAString & domain, IDNSSDResolveListener *listener, IDNSSDService **_retval NS_OUTPARAM)
214 {
215     CDNSSDService       *       service;
216         DNSServiceErrorType dnsErr;
217         nsresult                        err;
218
219         *_retval = NULL;
220         
221         fprintf( m_fp, "in Resolve( listener = 0x%x )\n", listener );
222         fflush( m_fp );
223
224         if ( !m_mainRef )
225         {
226                 err = NS_ERROR_NOT_AVAILABLE;
227                 goto exit;
228         }
229
230         try
231         {
232                 service = new CDNSSDService( m_mainRef, listener );
233         }
234         catch ( ... )
235         {
236                 service = NULL;
237         }
238         
239         if ( service == NULL )
240         {
241                 err = NS_ERROR_FAILURE;
242                 goto exit;
243         }
244
245         dnsErr = DNSServiceResolve( &service->m_subRef, kDNSServiceFlagsShareConnection, interfaceIndex, NS_ConvertUTF16toUTF8( name ).get(), NS_ConvertUTF16toUTF8( regtype ).get(), NS_ConvertUTF16toUTF8( domain ).get(), ( DNSServiceResolveReply ) ResolveReply, service );
246         
247         if ( dnsErr != kDNSServiceErr_NoError )
248         {
249                 err = NS_ERROR_FAILURE;
250                 goto exit;
251         }
252         
253         listener->AddRef();
254         service->AddRef();
255         *_retval = service;
256         err = NS_OK;
257         
258         fprintf( m_fp, "did DNSServiceResolve\n" );
259         fflush( m_fp );
260         
261 exit:
262         
263         if ( err && service )
264         {
265                 delete service;
266                 service = NULL;
267         }
268         
269         return err;
270 }
271
272
273 /* void stop (); */
274 NS_IMETHODIMP
275 CDNSSDService::Stop()
276 {
277     if ( m_subRef )
278         {
279                 DNSServiceRefDeallocate( m_subRef );
280                 m_subRef = NULL;
281         }
282         
283         return NS_OK;
284 }
285
286
287 void
288 CDNSSDService::Read( void * arg )
289 {
290         NS_PRECONDITION( arg != NULL, "arg is NULL" );
291         
292         NS_DispatchToMainThread( ( CDNSSDService* ) arg );
293 }
294
295
296 NS_IMETHODIMP
297 CDNSSDService::Run()
298 {
299         nsresult err;
300         
301         NS_PRECONDITION( m_mainRef != NULL, "m_mainRef is NULL" );
302
303         fprintf( m_fp, "in CDNSSDService::Run()\n" );
304         fflush( m_fp );
305         
306         m_job = NULL;
307
308         if ( DNSServiceProcessResult( m_mainRef ) == kDNSServiceErr_NoError )
309         {
310                 err = SetupNotifications();
311         }
312         else
313         {
314                 err = NS_ERROR_FAILURE;
315         }
316         
317         return err;
318 }
319
320
321 void DNSSD_API
322 CDNSSDService::BrowseReply
323                 (
324                 DNSServiceRef           sdRef,
325                 DNSServiceFlags         flags,
326                 uint32_t                        interfaceIndex,
327                 DNSServiceErrorType     errorCode,
328                 const char              *       serviceName,
329                 const char              *       regtype,
330                 const char              *       replyDomain,
331                 void                    *       context
332                 )
333 {
334         CDNSSDService * self = ( CDNSSDService* ) context;
335
336         fprintf( m_fp, "in browseReply: interfaceIndex = %d\n", interfaceIndex );
337         fflush( m_fp );
338
339         // This should never be NULL, but let's be defensive.
340         
341         if ( self != NULL )
342         {
343                 IDNSSDBrowseListener * listener = ( IDNSSDBrowseListener* ) self->m_listener;
344
345                 // Same for this
346
347                 if ( listener != NULL )
348                 {
349                         listener->OnBrowse( self, ( flags & kDNSServiceFlagsAdd ) ? PR_TRUE : PR_FALSE, interfaceIndex, errorCode, NS_ConvertUTF8toUTF16( serviceName ), NS_ConvertUTF8toUTF16( regtype ), NS_ConvertUTF8toUTF16( replyDomain ) );
350                 }
351         }
352 }
353
354
355 void DNSSD_API
356 CDNSSDService::ResolveReply
357                 (
358                 DNSServiceRef                   sdRef,
359                 DNSServiceFlags                 flags,
360                 uint32_t                                interfaceIndex,
361                 DNSServiceErrorType             errorCode,
362                 const char                      *       fullname,
363                 const char                      *       hosttarget,
364                 uint16_t                                port,
365                 uint16_t                                txtLen,
366                 const unsigned char     *       txtRecord,
367                 void                            *       context
368                 )
369 {
370         CDNSSDService * self = ( CDNSSDService* ) context;
371         
372         fprintf( m_fp, "in CDNSSDService::ResolveReply()\n" );
373         fflush( m_fp );
374
375         // This should never be NULL, but let's be defensive.
376         
377         if ( self != NULL )
378         {
379                 IDNSSDResolveListener * listener = ( IDNSSDResolveListener* ) self->m_listener;
380                 
381                 // Same for this
382
383                 if ( listener != NULL )
384                 {
385                         std::string             path = "";
386                         const void      *       value = NULL;
387                         uint8_t                 valueLen = 0;
388
389                         value = TXTRecordGetValuePtr( txtLen, txtRecord, "path", &valueLen );
390                         
391                         if ( value && valueLen )
392                         {
393                                 char * temp;
394                                 
395                                 temp = new char[ valueLen + 1 ];
396                                 
397                                 if ( temp )
398                                 {
399                                         memset( temp, 0, valueLen + 1 );
400                                         memcpy( temp, value, valueLen );
401                                         path = temp;
402                                         delete [] temp;
403                                 }
404                         }
405
406                         listener->OnResolve( self, interfaceIndex, errorCode, NS_ConvertUTF8toUTF16( fullname ), NS_ConvertUTF8toUTF16( hosttarget ) , ntohs( port ), NS_ConvertUTF8toUTF16( path.c_str() ) );
407                 }
408         }
409 }
410