]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSWindows/ControlPanel/ConfigPropertySheet.cpp
mDNSResponder-170.tar.gz
[apple/mdnsresponder.git] / mDNSWindows / ControlPanel / ConfigPropertySheet.cpp
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2002-2004 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 Change History (most recent first):
18
19 $Log: ConfigPropertySheet.cpp,v $
20 Revision 1.5 2006/08/14 23:25:28 cheshire
21 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
22
23 Revision 1.4 2005/10/05 20:46:50 herscher
24 <rdar://problem/4192011> Move Wide-Area preferences to another part of the registry so they don't removed during an update-install.
25
26 Revision 1.3 2005/03/03 19:55:22 shersche
27 <rdar://problem/4034481> ControlPanel source code isn't saving CVS log info
28
29
30 */
31
32 #include "ConfigPropertySheet.h"
33 #include <WinServices.h>
34 #include <process.h>
35
36 // Custom events
37
38 #define WM_DATAREADY ( WM_USER + 0x100 )
39 #define WM_REGISTRYCHANGED ( WM_USER + 0x101 )
40
41
42 IMPLEMENT_DYNCREATE(CConfigPropertySheet, CPropertySheet)
43
44
45 //---------------------------------------------------------------------------------------------------------------------------
46 // CConfigPropertySheet::CConfigPropertySheet
47 //---------------------------------------------------------------------------------------------------------------------------
48
49 CConfigPropertySheet::CConfigPropertySheet()
50 :
51 CPropertySheet(),
52 m_browseDomainsRef( NULL ),
53 m_regDomainsRef( NULL ),
54 m_thread( NULL ),
55 m_threadExited( NULL )
56 {
57 AddPage(&m_firstPage);
58 AddPage(&m_secondPage);
59 AddPage(&m_thirdPage);
60
61 InitializeCriticalSection( &m_lock );
62 }
63
64
65 //---------------------------------------------------------------------------------------------------------------------------
66 // CConfigPropertySheet::~CConfigPropertySheet
67 //---------------------------------------------------------------------------------------------------------------------------
68
69 CConfigPropertySheet::~CConfigPropertySheet()
70 {
71 DeleteCriticalSection( &m_lock );
72 }
73
74
75 BEGIN_MESSAGE_MAP(CConfigPropertySheet, CPropertySheet)
76 //{{AFX_MSG_MAP(CConfigPropertySheet)
77 //}}AFX_MSG_MAP
78 ON_MESSAGE( WM_DATAREADY, OnDataReady )
79 ON_MESSAGE( WM_REGISTRYCHANGED, OnRegistryChanged )
80 END_MESSAGE_MAP()
81
82
83 //---------------------------------------------------------------------------------------------------------------------------
84 // CConfigPropertySheet::OnInitDialog
85 //---------------------------------------------------------------------------------------------------------------------------
86
87 BOOL
88 CConfigPropertySheet::OnInitDialog()
89 {
90 OSStatus err;
91
92 BOOL b = CPropertySheet::OnInitDialog();
93
94 err = SetupBrowsing();
95 require_noerr( err, exit );
96
97 err = SetupRegistryNotifications();
98 require_noerr( err, exit );
99
100 exit:
101
102 return b;
103 }
104
105
106 //---------------------------------------------------------------------------------------------------------------------------
107 // CConfigPropertySheet::OnCommand
108 //---------------------------------------------------------------------------------------------------------------------------
109
110 BOOL
111 CConfigPropertySheet::OnCommand(WPARAM wParam, LPARAM lParam)
112 {
113 // Check if OK or Cancel was hit
114
115 if ( ( wParam == ID_WIZFINISH ) || ( wParam == IDOK ) || ( wParam == IDCANCEL ) )
116 {
117 OnEndDialog();
118 }
119
120 return CPropertySheet::OnCommand(wParam, lParam);
121 }
122
123
124 //---------------------------------------------------------------------------------------------------------------------------
125 // CConfigPropertySheet::OnDataReady
126 //---------------------------------------------------------------------------------------------------------------------------
127
128 LONG
129 CConfigPropertySheet::OnDataReady(WPARAM inWParam, LPARAM inLParam)
130 {
131 if (WSAGETSELECTERROR(inLParam) && !(HIWORD(inLParam)))
132 {
133 dlog( kDebugLevelError, "OnSocket: window error\n" );
134 }
135 else
136 {
137 SOCKET sock = (SOCKET) inWParam;
138
139 if ( m_browseDomainsRef && DNSServiceRefSockFD( m_browseDomainsRef ) == (int) sock )
140 {
141 DNSServiceProcessResult( m_browseDomainsRef );
142 }
143 else if ( m_regDomainsRef && DNSServiceRefSockFD( m_regDomainsRef ) == (int) sock )
144 {
145 DNSServiceProcessResult( m_regDomainsRef );
146 }
147 }
148
149 return 0;
150 }
151
152
153 //---------------------------------------------------------------------------------------------------------------------------
154 // CConfigPropertySheet::OnRegistryChanged
155 //---------------------------------------------------------------------------------------------------------------------------
156
157 afx_msg LONG
158 CConfigPropertySheet::OnRegistryChanged( WPARAM inWParam, LPARAM inLParam )
159 {
160 DEBUG_UNUSED( inWParam );
161 DEBUG_UNUSED( inLParam );
162
163 if ( GetActivePage() == &m_firstPage )
164 {
165 m_firstPage.OnRegistryChanged();
166 }
167
168 return 0;
169 }
170
171
172 //---------------------------------------------------------------------------------------------------------------------------
173 // CConfigPropertySheet::OnEndDialog
174 //---------------------------------------------------------------------------------------------------------------------------
175
176 void
177 CConfigPropertySheet::OnEndDialog()
178 {
179 OSStatus err;
180
181 err = TearDownRegistryNotifications();
182 check_noerr( err );
183
184 err = TearDownBrowsing();
185 check_noerr( err );
186 }
187
188
189 //---------------------------------------------------------------------------------------------------------------------------
190 // CConfigPropertySheet::SetupBrowsing
191 //---------------------------------------------------------------------------------------------------------------------------
192
193 OSStatus
194 CConfigPropertySheet::SetupBrowsing()
195 {
196 OSStatus err;
197
198 // Start browsing for browse domains
199
200 err = DNSServiceEnumerateDomains( &m_browseDomainsRef, kDNSServiceFlagsBrowseDomains, 0, BrowseDomainsReply, this );
201 require_noerr( err, exit );
202
203 err = WSAAsyncSelect( DNSServiceRefSockFD( m_browseDomainsRef ), m_hWnd, WM_DATAREADY, FD_READ|FD_CLOSE );
204 require_noerr( err, exit );
205
206 // Start browsing for registration domains
207
208 err = DNSServiceEnumerateDomains( &m_regDomainsRef, kDNSServiceFlagsRegistrationDomains, 0, RegDomainsReply, this );
209 require_noerr( err, exit );
210
211 err = WSAAsyncSelect( DNSServiceRefSockFD( m_regDomainsRef ), m_hWnd, WM_DATAREADY, FD_READ|FD_CLOSE );
212 require_noerr( err, exit );
213
214 exit:
215
216 if ( err )
217 {
218 TearDownBrowsing();
219 }
220
221 return err;
222 }
223
224
225 //---------------------------------------------------------------------------------------------------------------------------
226 // CConfigPropertySheet::TearDownBrowsing
227 //---------------------------------------------------------------------------------------------------------------------------
228
229 OSStatus
230 CConfigPropertySheet::TearDownBrowsing()
231 {
232 OSStatus err = kNoErr;
233
234 if ( m_browseDomainsRef )
235 {
236 err = WSAAsyncSelect( DNSServiceRefSockFD( m_browseDomainsRef ), m_hWnd, 0, 0 );
237 check_noerr( err );
238
239 DNSServiceRefDeallocate( m_browseDomainsRef );
240
241 m_browseDomainsRef = NULL;
242 }
243
244 if ( m_regDomainsRef )
245 {
246 err = WSAAsyncSelect( DNSServiceRefSockFD( m_regDomainsRef ), m_hWnd, 0, 0 );
247 check_noerr( err );
248
249 DNSServiceRefDeallocate( m_regDomainsRef );
250
251 m_regDomainsRef = NULL;
252 }
253
254 return err;
255 }
256
257
258 //---------------------------------------------------------------------------------------------------------------------------
259 // CConfigPropertySheet::SetupRegistryNotifications
260 //---------------------------------------------------------------------------------------------------------------------------
261
262 OSStatus
263 CConfigPropertySheet::SetupRegistryNotifications()
264 {
265 unsigned int threadId;
266 OSStatus err;
267
268 check( m_threadExited == NULL );
269 check( m_thread == NULL );
270
271 err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\DynDNS\\State\\Hostnames", &m_statusKey );
272 require_noerr( err, exit );
273
274 m_threadExited = CreateEvent( NULL, FALSE, FALSE, NULL );
275 err = translate_errno( m_threadExited, (OSStatus) GetLastError(), kUnknownErr );
276 require_noerr( err, exit );
277
278 // Create thread with _beginthreadex() instead of CreateThread() to avoid memory leaks when using static run-time
279 // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
280
281 m_thread = (HANDLE) _beginthreadex_compat( NULL, 0, WatchRegistry, this, 0, &threadId );
282 err = translate_errno( m_thread, (OSStatus) GetLastError(), kUnknownErr );
283 require_noerr( err, exit );
284
285 exit:
286
287 if ( err )
288 {
289 TearDownRegistryNotifications();
290 }
291
292 return err;
293 }
294
295
296 //---------------------------------------------------------------------------------------------------------------------------
297 // CConfigPropertySheet::TearDownRegistryNotifications
298 //---------------------------------------------------------------------------------------------------------------------------
299
300 OSStatus
301 CConfigPropertySheet::TearDownRegistryNotifications()
302 {
303 OSStatus err = kNoErr;
304
305 if ( m_statusKey )
306 {
307 EnterCriticalSection( &m_lock );
308
309 RegCloseKey( m_statusKey );
310 m_statusKey = NULL;
311
312 LeaveCriticalSection( &m_lock );
313 }
314
315 if ( m_threadExited )
316 {
317 err = WaitForSingleObject( m_threadExited, 5 * 1000 );
318 require_noerr( err, exit );
319 }
320
321 exit:
322
323 if ( m_threadExited )
324 {
325 CloseHandle( m_threadExited );
326 m_threadExited = NULL;
327 }
328
329 if ( m_thread )
330 {
331 CloseHandle( m_thread );
332 m_thread = NULL;
333 }
334
335 return err;
336 }
337
338
339 //---------------------------------------------------------------------------------------------------------------------------
340 // CConfigPropertySheet::DecodeDomainName
341 //---------------------------------------------------------------------------------------------------------------------------
342
343 OSStatus
344 CConfigPropertySheet::DecodeDomainName( const char * raw, CString & decoded )
345 {
346 char nextLabel[128] = "\0";
347 char decodedDomainString[kDNSServiceMaxDomainName];
348 char * buffer = (char *) raw;
349 int labels = 0, i;
350 char text[64];
351 const char *label[128];
352 OSStatus err;
353
354 // Initialize
355
356 decodedDomainString[0] = '\0';
357
358 // Count the labels
359
360 while ( *buffer )
361 {
362 label[labels++] = buffer;
363 buffer = (char *) GetNextLabel(buffer, text);
364 }
365
366 buffer = (char*) raw;
367
368 for (i = 0; i < labels; i++)
369 {
370 buffer = (char *)GetNextLabel(buffer, nextLabel);
371 strcat(decodedDomainString, nextLabel);
372 strcat(decodedDomainString, ".");
373 }
374
375 // Remove trailing dot from domain name.
376
377 decodedDomainString[ strlen( decodedDomainString ) - 1 ] = '\0';
378
379 // Convert to Unicode
380
381 err = UTF8StringToStringObject( decodedDomainString, decoded );
382
383 return err;
384 }
385
386
387 //---------------------------------------------------------------------------------------------------------------------------
388 // CConfigPropertySheet::GetNextLabel
389 //---------------------------------------------------------------------------------------------------------------------------
390
391 const char*
392 CConfigPropertySheet::GetNextLabel( const char * cstr, char label[64] )
393 {
394 char *ptr = label;
395 while (*cstr && *cstr != '.') // While we have characters in the label...
396 {
397 char c = *cstr++;
398 if (c == '\\')
399 {
400 c = *cstr++;
401 if (isdigit(cstr[-1]) && isdigit(cstr[0]) && isdigit(cstr[1]))
402 {
403 int v0 = cstr[-1] - '0'; // then interpret as three-digit decimal
404 int v1 = cstr[ 0] - '0';
405 int v2 = cstr[ 1] - '0';
406 int val = v0 * 100 + v1 * 10 + v2;
407 if (val <= 255) { c = (char)val; cstr += 2; } // If valid three-digit decimal value, use it
408 }
409 }
410 *ptr++ = c;
411 if (ptr >= label+64) return(NULL);
412 }
413 if (*cstr) cstr++; // Skip over the trailing dot (if present)
414 *ptr++ = 0;
415 return(cstr);
416 }
417
418
419 //---------------------------------------------------------------------------------------------------------------------------
420 // CConfigPropertySheet::BrowseDomainsReply
421 //---------------------------------------------------------------------------------------------------------------------------
422
423 void DNSSD_API
424 CConfigPropertySheet::BrowseDomainsReply
425 (
426 DNSServiceRef sdRef,
427 DNSServiceFlags flags,
428 uint32_t interfaceIndex,
429 DNSServiceErrorType errorCode,
430 const char * replyDomain,
431 void * context
432 )
433 {
434 CConfigPropertySheet * self = reinterpret_cast<CConfigPropertySheet*>(context);
435 CString decoded;
436 OSStatus err;
437
438 DEBUG_UNUSED( sdRef );
439 DEBUG_UNUSED( interfaceIndex );
440
441 if ( errorCode )
442 {
443 goto exit;
444 }
445
446 check( replyDomain );
447
448 // Ignore local domains
449
450 if ( strcmp( replyDomain, "local." ) == 0 )
451 {
452 goto exit;
453 }
454
455
456
457 err = self->DecodeDomainName( replyDomain, decoded );
458 require_noerr( err, exit );
459
460 // Remove trailing '.'
461
462 decoded.TrimRight( '.' );
463
464 if ( flags & kDNSServiceFlagsAdd )
465 {
466 self->m_browseDomains.push_back( decoded );
467 }
468 else
469 {
470 self->m_browseDomains.remove( decoded );
471 }
472
473 exit:
474
475 return;
476 }
477
478
479 //---------------------------------------------------------------------------------------------------------------------------
480 // CConfigPropertySheet::RegDomainsReply
481 //---------------------------------------------------------------------------------------------------------------------------
482
483 void DNSSD_API
484 CConfigPropertySheet::RegDomainsReply
485 (
486 DNSServiceRef sdRef,
487 DNSServiceFlags flags,
488 uint32_t interfaceIndex,
489 DNSServiceErrorType errorCode,
490 const char * replyDomain,
491 void * context
492 )
493 {
494 CConfigPropertySheet * self = reinterpret_cast<CConfigPropertySheet*>(context);
495 CString decoded;
496 OSStatus err;
497
498 DEBUG_UNUSED( sdRef );
499 DEBUG_UNUSED( interfaceIndex );
500
501 if ( errorCode )
502 {
503 goto exit;
504 }
505
506 check( replyDomain );
507
508 // Ignore local domains
509
510 if ( strcmp( replyDomain, "local." ) == 0 )
511 {
512 goto exit;
513 }
514
515 err = self->DecodeDomainName( replyDomain, decoded );
516 require_noerr( err, exit );
517
518 // Remove trailing '.'
519
520 decoded.TrimRight( '.' );
521
522 if ( flags & kDNSServiceFlagsAdd )
523 {
524 if ( self->GetActivePage() == &self->m_secondPage )
525 {
526 self->m_secondPage.OnAddRegistrationDomain( decoded );
527 }
528
529 self->m_regDomains.push_back( decoded );
530 }
531 else
532 {
533 if ( self->GetActivePage() == &self->m_secondPage )
534 {
535 self->m_secondPage.OnRemoveRegistrationDomain( decoded );
536 }
537
538 self->m_regDomains.remove( decoded );
539 }
540
541 exit:
542
543 return;
544 }
545
546
547 //---------------------------------------------------------------------------------------------------------------------------
548 // CConfigPropertySheet::WatchRegistry
549 //---------------------------------------------------------------------------------------------------------------------------
550
551 unsigned WINAPI
552 CConfigPropertySheet::WatchRegistry ( LPVOID inParam )
553 {
554 bool done = false;
555
556 CConfigPropertySheet * self = reinterpret_cast<CConfigPropertySheet*>(inParam);
557 check( self );
558
559 while ( !done )
560 {
561 RegNotifyChangeKeyValue( self->m_statusKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET, NULL, FALSE );
562
563 EnterCriticalSection( &self->m_lock );
564
565 done = ( self->m_statusKey == NULL ) ? true : false;
566
567 if ( !done )
568 {
569 self->PostMessage( WM_REGISTRYCHANGED, 0, 0 );
570 }
571
572 LeaveCriticalSection( &self->m_lock );
573 }
574
575 SetEvent( self->m_threadExited );
576
577 return 0;
578 }