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