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