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