]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSWindows/SystemService/Service.c
mDNSResponder-878.270.2.tar.gz
[apple/mdnsresponder.git] / mDNSWindows / SystemService / Service.c
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2003-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
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <crtdbg.h>
21 #include <stdarg.h>
22 #include <stddef.h>
23
24 #include "Poll.h"
25 #include "CommonServices.h"
26 #include "DebugServices.h"
27 #include "RegNames.h"
28
29 #include "uds_daemon.h"
30 #include "GenLinkedList.h"
31 #include "Service.h"
32 #include "EventLog.h"
33
34 #include "Resource.h"
35
36 #include "mDNSEmbeddedAPI.h"
37 #include "uDNS.h"
38 #include "mDNSWin32.h"
39 #include "mDNSDebug.h"
40
41 #include "Firewall.h"
42
43 #if( !TARGET_OS_WINDOWS_CE )
44 #include <mswsock.h>
45 #include <process.h>
46 #include <ipExport.h>
47 #include <ws2def.h>
48 #include <ws2ipdef.h>
49 #include <iphlpapi.h>
50 #include <netioapi.h>
51 #include <iptypes.h>
52 #include <powrprof.h>
53 #endif
54
55 #ifndef HeapEnableTerminationOnCorruption
56 # define HeapEnableTerminationOnCorruption (HEAP_INFORMATION_CLASS)1
57 #endif
58
59 #if 0
60 #pragma mark == Constants ==
61 #endif
62
63 //===========================================================================================================================
64 // Constants
65 //===========================================================================================================================
66
67 #define DEBUG_NAME "[mDNSWin32] "
68 #define kServiceFirewallName L"Bonjour"
69 #define kServiceDependencies TEXT("Tcpip\0\0")
70 #define kDNSServiceCacheEntryCountDefault 512
71 #define kRetryFirewallPeriod 30 * 1000
72 #define kDefValueSize MAX_PATH + 1
73 #define kZeroIndex 0
74 #define kDefaultRouteMetric 399
75 #define kSecondsTo100NSUnits ( 10 * 1000 * 1000 )
76 #define kSPSMaintenanceWakePeriod -30
77 #define kWaitToRetry (60 * 5)
78
79 #define RR_CACHE_SIZE 500
80 static CacheEntity gRRCache[RR_CACHE_SIZE];
81 #if 0
82 #pragma mark == Structures ==
83 #endif
84
85 #if 0
86 #pragma mark == Prototypes ==
87 #endif
88
89 //===========================================================================================================================
90 // Prototypes
91 //===========================================================================================================================
92 static void Usage( void );
93 static BOOL WINAPI ConsoleControlHandler( DWORD inControlEvent );
94 static OSStatus InstallService( LPCTSTR inName, LPCTSTR inDisplayName, LPCTSTR inDescription, LPCTSTR inPath );
95 static OSStatus RemoveService( LPCTSTR inName );
96 static OSStatus SetServiceParameters();
97 static OSStatus GetServiceParameters();
98 static OSStatus CheckFirewall();
99 static OSStatus SetServiceInfo( SC_HANDLE inSCM, LPCTSTR inServiceName, LPCTSTR inDescription );
100 static void ReportStatus( int inType, const char *inFormat, ... );
101
102 static void WINAPI ServiceMain( DWORD argc, LPTSTR argv[] );
103 static OSStatus ServiceSetupEventLogging( void );
104 static DWORD WINAPI ServiceControlHandler( DWORD inControl, DWORD inEventType, LPVOID inEventData, LPVOID inContext );
105
106 static OSStatus ServiceRun( int argc, LPTSTR argv[] );
107 static void ServiceStop( void );
108
109 static OSStatus ServiceSpecificInitialize( int argc, LPTSTR argv[] );
110 static OSStatus ServiceSpecificRun( int argc, LPTSTR argv[] );
111 static OSStatus ServiceSpecificStop( void );
112 static void ServiceSpecificFinalize( int argc, LPTSTR argv[] );
113 static mStatus SetupServiceEvents();
114 static mStatus TearDownServiceEvents();
115 static mStatus SetupNotifications();
116 static mStatus TearDownNotifications();
117 static void CALLBACK StopNotification( HANDLE event, void * context );
118 static void CALLBACK PowerSuspendNotification( HANDLE event, void * context );
119 static void CALLBACK PowerResumeNotification( HANDLE event, void * context );
120 static void CALLBACK InterfaceListNotification( SOCKET socket, LPWSANETWORKEVENTS event, void *context );
121 static void CALLBACK ComputerDescriptionNotification( HANDLE event, void *context );
122 static void CALLBACK TCPChangedNotification( HANDLE event, void *context );
123 static void CALLBACK DDNSChangedNotification( HANDLE event, void *context );
124 static void CALLBACK FileSharingChangedNotification( HANDLE event, void *context );
125 static void CALLBACK FirewallChangedNotification( HANDLE event, void *context );
126 static void CALLBACK AdvertisedServicesChangedNotification( HANDLE event, void *context );
127 static void CALLBACK SPSWakeupNotification( HANDLE event, void *context );
128 static void CALLBACK SPSSleepNotification( HANDLE event, void *context );
129 static void CALLBACK UDSAcceptNotification( SOCKET sock, LPWSANETWORKEVENTS event, void *context );
130 static void CALLBACK UDSReadNotification( SOCKET sock, LPWSANETWORKEVENTS event, void *context );
131 static void CoreCallback(mDNS * const inMDNS, mStatus result);
132 static mDNSu8 SystemWakeForNetworkAccess( LARGE_INTEGER * timeout );
133 static OSStatus GetRouteDestination(DWORD * ifIndex, DWORD * address);
134 static OSStatus SetLLRoute( mDNS * const inMDNS );
135 static bool HaveRoute( PMIB_IPFORWARDROW rowExtant, unsigned long addr, unsigned long metric );
136 static bool IsValidAddress( const char * addr );
137 static bool IsNortelVPN( IP_ADAPTER_INFO * pAdapter );
138 static bool IsJuniperVPN( IP_ADAPTER_INFO * pAdapter );
139 static bool IsCiscoVPN( IP_ADAPTER_INFO * pAdapter );
140 static const char * strnistr( const char * string, const char * subString, size_t max );
141
142 #if defined(UNICODE)
143 # define StrLen(X) wcslen(X)
144 # define StrCmp(X,Y) wcscmp(X,Y)
145 #else
146 # define StrLen(X) strlen(X)
147 # define StrCmp(X,Y) strcmp(X,Y)
148 #endif
149
150
151 #define kLLNetworkAddr "169.254.0.0"
152 #define kLLNetworkAddrMask "255.255.0.0"
153
154
155 #include "mDNSEmbeddedAPI.h"
156
157 #if 0
158 #pragma mark == Globals ==
159 #endif
160
161 //===========================================================================================================================
162 // Globals
163 //===========================================================================================================================
164 #define gMDNSRecord mDNSStorage
165 DEBUG_LOCAL mDNS_PlatformSupport gPlatformStorage;
166 DEBUG_LOCAL BOOL gServiceQuietMode = FALSE;
167 DEBUG_LOCAL SERVICE_TABLE_ENTRY gServiceDispatchTable[] =
168 {
169 { kServiceName, ServiceMain },
170 { NULL, NULL }
171 };
172 DEBUG_LOCAL HANDLE gStopEvent = NULL;
173 DEBUG_LOCAL HANDLE gPowerSuspendEvent = NULL;
174 DEBUG_LOCAL HANDLE gPowerSuspendAckEvent = NULL;
175 DEBUG_LOCAL HANDLE gPowerResumeEvent = NULL;
176 DEBUG_LOCAL SOCKET gInterfaceListChangedSocket = INVALID_SOCKET;
177 DEBUG_LOCAL HKEY gDescKey = NULL;
178 DEBUG_LOCAL HANDLE gDescChangedEvent = NULL; // Computer description changed event
179 DEBUG_LOCAL HKEY gTcpipKey = NULL;
180 DEBUG_LOCAL HANDLE gTcpipChangedEvent = NULL; // TCP/IP config changed
181 DEBUG_LOCAL HKEY gDdnsKey = NULL;
182 DEBUG_LOCAL HANDLE gDdnsChangedEvent = NULL; // DynDNS config changed
183 DEBUG_LOCAL HKEY gFileSharingKey = NULL;
184 DEBUG_LOCAL HANDLE gFileSharingChangedEvent = NULL; // File Sharing changed
185 DEBUG_LOCAL HKEY gFirewallKey = NULL;
186 DEBUG_LOCAL HANDLE gFirewallChangedEvent = NULL; // Firewall changed
187 DEBUG_LOCAL HKEY gAdvertisedServicesKey = NULL;
188 DEBUG_LOCAL HANDLE gAdvertisedServicesChangedEvent = NULL; // Advertised services changed
189 DEBUG_LOCAL SERVICE_STATUS gServiceStatus;
190 DEBUG_LOCAL SERVICE_STATUS_HANDLE gServiceStatusHandle = NULL;
191 DEBUG_LOCAL HANDLE gServiceEventSource = NULL;
192 DEBUG_LOCAL bool gServiceAllowRemote = false;
193 DEBUG_LOCAL int gServiceCacheEntryCount = 0; // 0 means to use the DNS-SD default.
194 DEBUG_LOCAL bool gServiceManageLLRouting = true;
195 DEBUG_LOCAL HANDLE gSPSWakeupEvent = NULL;
196 DEBUG_LOCAL HANDLE gSPSSleepEvent = NULL;
197 DEBUG_LOCAL SocketRef gUDSSocket = 0;
198 DEBUG_LOCAL udsEventCallback gUDSCallback = NULL;
199 DEBUG_LOCAL BOOL gRetryFirewall = FALSE;
200
201 typedef DWORD ( WINAPI * GetIpInterfaceEntryFunctionPtr )( PMIB_IPINTERFACE_ROW );
202 mDNSlocal HMODULE gIPHelperLibraryInstance = NULL;
203 mDNSlocal GetIpInterfaceEntryFunctionPtr gGetIpInterfaceEntryFunctionPtr = NULL;
204
205
206 #if 0
207 #pragma mark -
208 #endif
209
210 //===========================================================================================================================
211 // Main
212 //===========================================================================================================================
213 int Main( int argc, LPTSTR argv[] )
214 {
215 OSStatus err;
216 BOOL ok;
217 BOOL start;
218 int i;
219
220 HeapSetInformation( NULL, HeapEnableTerminationOnCorruption, NULL, 0 );
221
222 debug_initialize( kDebugOutputTypeMetaConsole );
223 debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelVerbose );
224
225 // Default to automatically starting the service dispatcher if no extra arguments are specified.
226
227 start = ( argc <= 1 );
228
229 // Parse arguments.
230
231 for( i = 1; i < argc; ++i )
232 {
233 if( StrCmp( argv[ i ], TEXT("-install") ) == 0 ) // Install
234 {
235 TCHAR desc[ 256 ];
236
237 desc[ 0 ] = 0;
238 LoadString( GetModuleHandle( NULL ), IDS_SERVICE_DESCRIPTION, desc, sizeof( desc ) );
239 err = InstallService( kServiceName, kServiceName, desc, argv[0] );
240 if( err )
241 {
242 ReportStatus( EVENTLOG_ERROR_TYPE, "install service failed (%d)\n", err );
243 goto exit;
244 }
245 }
246 else if( StrCmp( argv[ i ], TEXT("-remove") ) == 0 ) // Remove
247 {
248 err = RemoveService( kServiceName );
249 if( err )
250 {
251 ReportStatus( EVENTLOG_ERROR_TYPE, "remove service failed (%d)\n", err );
252 goto exit;
253 }
254 }
255 else if( StrCmp( argv[ i ], TEXT("-start") ) == 0 ) // Start
256 {
257 start = TRUE;
258 }
259 else if( StrCmp( argv[ i ], TEXT("-server") ) == 0 ) // Server
260 {
261 err = RunDirect( argc, argv );
262 if( err )
263 {
264 ReportStatus( EVENTLOG_ERROR_TYPE, "run service directly failed (%d)\n", err );
265 }
266 goto exit;
267 }
268 else if( StrCmp( argv[ i ], TEXT("-q") ) == 0 ) // Quiet Mode (toggle)
269 {
270 gServiceQuietMode = !gServiceQuietMode;
271 }
272 else if( ( StrCmp( argv[ i ], TEXT("-help") ) == 0 ) || // Help
273 ( StrCmp( argv[ i ], TEXT("-h") ) == 0 ) )
274 {
275 Usage();
276 err = 0;
277 break;
278 }
279 else
280 {
281 Usage();
282 err = kParamErr;
283 break;
284 }
285 }
286
287 // Start the service dispatcher if requested. This does not return until all services have terminated. If any
288 // global initialization is needed, it should be done before starting the service dispatcher, but only if it
289 // will take less than 30 seconds. Otherwise, use a separate thread for it and start the dispatcher immediately.
290
291 if( start )
292 {
293 ok = StartServiceCtrlDispatcher( gServiceDispatchTable );
294 err = translate_errno( ok, (OSStatus) GetLastError(), kInUseErr );
295 if( err != kNoErr )
296 {
297 ReportStatus( EVENTLOG_ERROR_TYPE, "start service dispatcher failed (%d)\n", err );
298 goto exit;
299 }
300 }
301 err = 0;
302
303 exit:
304 dlog( kDebugLevelTrace, DEBUG_NAME "exited (%d %m)\n", err, err );
305 _CrtDumpMemoryLeaks();
306 return( (int) err );
307 }
308
309 //===========================================================================================================================
310 // Usage
311 //===========================================================================================================================
312
313 static void Usage( void )
314 {
315 fprintf( stderr, "\n" );
316 fprintf( stderr, "mDNSResponder 1.0d1\n" );
317 fprintf( stderr, "\n" );
318 fprintf( stderr, " <no args> Runs the service normally\n" );
319 fprintf( stderr, " -install Creates the service and starts it\n" );
320 fprintf( stderr, " -remove Stops the service and deletes it\n" );
321 fprintf( stderr, " -start Starts the service dispatcher after processing all other arguments\n" );
322 fprintf( stderr, " -server Runs the service directly as a server (for debugging)\n" );
323 fprintf( stderr, " -q Toggles Quiet Mode (no events or output)\n" );
324 fprintf( stderr, " -remote Allow remote connections\n" );
325 fprintf( stderr, " -cache n Number of mDNS cache entries (defaults to %d)\n", kDNSServiceCacheEntryCountDefault );
326 fprintf( stderr, " -h[elp] Display Help/Usage\n" );
327 fprintf( stderr, "\n" );
328 }
329
330 //===========================================================================================================================
331 // ConsoleControlHandler
332 //===========================================================================================================================
333
334 static BOOL WINAPI ConsoleControlHandler( DWORD inControlEvent )
335 {
336 BOOL handled;
337 OSStatus err;
338
339 handled = FALSE;
340 switch( inControlEvent )
341 {
342 case CTRL_C_EVENT:
343 case CTRL_BREAK_EVENT:
344 case CTRL_CLOSE_EVENT:
345 case CTRL_LOGOFF_EVENT:
346 case CTRL_SHUTDOWN_EVENT:
347 err = ServiceSpecificStop();
348 require_noerr( err, exit );
349
350 handled = TRUE;
351 break;
352
353 default:
354 break;
355 }
356
357 exit:
358 return( handled );
359 }
360
361 //===========================================================================================================================
362 // InstallService
363 //===========================================================================================================================
364
365 static OSStatus InstallService( LPCTSTR inName, LPCTSTR inDisplayName, LPCTSTR inDescription, LPCTSTR inPath )
366 {
367 OSStatus err;
368 SC_HANDLE scm;
369 SC_HANDLE service;
370 BOOL ok;
371 TCHAR fullPath[ MAX_PATH ];
372 TCHAR * namePtr;
373 DWORD size;
374
375 scm = NULL;
376 service = NULL;
377
378 // Get a full path to the executable since a relative path may have been specified.
379
380 size = GetFullPathName( inPath, MAX_PATH, fullPath, &namePtr );
381 err = translate_errno( size > 0, (OSStatus) GetLastError(), kPathErr );
382 require_noerr( err, exit );
383
384 // Create the service and start it.
385
386 scm = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
387 err = translate_errno( scm, (OSStatus) GetLastError(), kOpenErr );
388 require_noerr( err, exit );
389
390 service = CreateService( scm, inName, inDisplayName, SERVICE_ALL_ACCESS, SERVICE_WIN32_SHARE_PROCESS,
391 SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, fullPath, NULL, NULL, kServiceDependencies,
392 NULL, NULL );
393 err = translate_errno( service, (OSStatus) GetLastError(), kDuplicateErr );
394 require_noerr( err, exit );
395
396 err = SetServiceParameters();
397 check_noerr( err );
398
399 if( inDescription )
400 {
401 err = SetServiceInfo( scm, inName, inDescription );
402 check_noerr( err );
403 }
404
405 ok = StartService( service, 0, NULL );
406 err = translate_errno( ok, (OSStatus) GetLastError(), kInUseErr );
407 require_noerr( err, exit );
408
409 ReportStatus( EVENTLOG_SUCCESS, "installed service\n" );
410 err = kNoErr;
411
412 exit:
413 if( service )
414 {
415 CloseServiceHandle( service );
416 }
417 if( scm )
418 {
419 CloseServiceHandle( scm );
420 }
421 return( err );
422 }
423
424 //===========================================================================================================================
425 // RemoveService
426 //===========================================================================================================================
427
428 static OSStatus RemoveService( LPCTSTR inName )
429 {
430 OSStatus err;
431 SC_HANDLE scm;
432 SC_HANDLE service;
433 BOOL ok;
434 SERVICE_STATUS status;
435
436 scm = NULL;
437 service = NULL;
438
439 // Open a connection to the service.
440
441 scm = OpenSCManager( 0, 0, SC_MANAGER_ALL_ACCESS );
442 err = translate_errno( scm, (OSStatus) GetLastError(), kOpenErr );
443 require_noerr( err, exit );
444
445 service = OpenService( scm, inName, SERVICE_STOP | SERVICE_QUERY_STATUS | DELETE );
446 err = translate_errno( service, (OSStatus) GetLastError(), kNotFoundErr );
447 require_noerr( err, exit );
448
449 // Stop the service, if it is not already stopped, then delete it.
450
451 ok = QueryServiceStatus( service, &status );
452 err = translate_errno( ok, (OSStatus) GetLastError(), kAuthenticationErr );
453 require_noerr( err, exit );
454
455 if( status.dwCurrentState != SERVICE_STOPPED )
456 {
457 ok = ControlService( service, SERVICE_CONTROL_STOP, &status );
458 check_translated_errno( ok, (OSStatus) GetLastError(), kAuthenticationErr );
459 }
460
461 ok = DeleteService( service );
462 err = translate_errno( ok, (OSStatus) GetLastError(), kDeletedErr );
463 require_noerr( err, exit );
464
465 ReportStatus( EVENTLOG_SUCCESS, "Removed service\n" );
466 err = ERROR_SUCCESS;
467
468 exit:
469 if( service )
470 {
471 CloseServiceHandle( service );
472 }
473 if( scm )
474 {
475 CloseServiceHandle( scm );
476 }
477 return( err );
478 }
479
480
481
482 //===========================================================================================================================
483 // SetServiceParameters
484 //===========================================================================================================================
485
486 static OSStatus SetServiceParameters()
487 {
488 DWORD value;
489 DWORD valueLen = sizeof(DWORD);
490 DWORD type;
491 OSStatus err;
492 HKEY key;
493
494 key = NULL;
495
496 //
497 // Add/Open Parameters section under service entry in registry
498 //
499 err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode, &key );
500 require_noerr( err, exit );
501
502 //
503 // If the value isn't already there, then we create it
504 //
505 err = RegQueryValueEx(key, kServiceManageLLRouting, 0, &type, (LPBYTE) &value, &valueLen);
506
507 if (err != ERROR_SUCCESS)
508 {
509 value = 1;
510
511 err = RegSetValueEx( key, kServiceManageLLRouting, 0, REG_DWORD, (const LPBYTE) &value, sizeof(DWORD) );
512 require_noerr( err, exit );
513 }
514
515 exit:
516
517 if ( key )
518 {
519 RegCloseKey( key );
520 }
521
522 return( err );
523 }
524
525
526
527 //===========================================================================================================================
528 // GetServiceParameters
529 //===========================================================================================================================
530
531 static OSStatus GetServiceParameters()
532 {
533 DWORD value;
534 DWORD valueLen;
535 DWORD type;
536 OSStatus err;
537 HKEY key;
538
539 key = NULL;
540
541 //
542 // Add/Open Parameters section under service entry in registry
543 //
544 err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode, &key );
545 require_noerr( err, exit );
546
547 valueLen = sizeof(DWORD);
548 err = RegQueryValueEx(key, kServiceManageLLRouting, 0, &type, (LPBYTE) &value, &valueLen);
549 if (err == ERROR_SUCCESS)
550 {
551 gServiceManageLLRouting = (value) ? true : false;
552 }
553
554 valueLen = sizeof(DWORD);
555 err = RegQueryValueEx(key, kServiceCacheEntryCount, 0, &type, (LPBYTE) &value, &valueLen);
556 if (err == ERROR_SUCCESS)
557 {
558 gServiceCacheEntryCount = value;
559 }
560
561 exit:
562
563 if ( key )
564 {
565 RegCloseKey( key );
566 }
567
568 return( err );
569 }
570
571
572 //===========================================================================================================================
573 // CheckFirewall
574 //===========================================================================================================================
575
576 static OSStatus CheckFirewall()
577 {
578 DWORD value;
579 DWORD valueLen;
580 DWORD type;
581 ENUM_SERVICE_STATUS * lpService = NULL;
582 SC_HANDLE sc = NULL;
583 HKEY key = NULL;
584 BOOL ok;
585 DWORD bytesNeeded = 0;
586 DWORD srvCount;
587 DWORD resumeHandle = 0;
588 DWORD srvType;
589 DWORD srvState;
590 DWORD dwBytes = 0;
591 DWORD i;
592 BOOL isRunning = FALSE;
593 OSStatus err = kUnknownErr;
594
595 // Check to see if the firewall service is running. If it isn't, then
596 // we want to return immediately
597
598 sc = OpenSCManager( NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE );
599 err = translate_errno( sc, GetLastError(), kUnknownErr );
600 require_noerr( err, exit );
601
602 srvType = SERVICE_WIN32;
603 srvState = SERVICE_STATE_ALL;
604
605 for ( ;; )
606 {
607 // Call EnumServicesStatus using the handle returned by OpenSCManager
608
609 ok = EnumServicesStatus ( sc, srvType, srvState, lpService, dwBytes, &bytesNeeded, &srvCount, &resumeHandle );
610
611 if ( ok || ( GetLastError() != ERROR_MORE_DATA ) )
612 {
613 break;
614 }
615
616 if ( lpService )
617 {
618 free( lpService );
619 }
620
621 dwBytes = bytesNeeded;
622
623 lpService = ( ENUM_SERVICE_STATUS* ) malloc( dwBytes );
624 require_action( lpService, exit, err = mStatus_NoMemoryErr );
625 }
626
627 err = translate_errno( ok, GetLastError(), kUnknownErr );
628 require_noerr( err, exit );
629
630 for ( i = 0; i < srvCount; i++ )
631 {
632 if ( wcscmp( lpService[i].lpServiceName, L"SharedAccess" ) == 0 )
633 {
634 if ( lpService[i].ServiceStatus.dwCurrentState == SERVICE_RUNNING )
635 {
636 isRunning = TRUE;
637 }
638
639 break;
640 }
641 }
642
643 require_action( isRunning, exit, err = kUnknownErr );
644
645 // Check to see if we've managed the firewall.
646 // This package might have been installed, then
647 // the OS was upgraded to SP2 or above. If that's
648 // the case, then we need to manipulate the firewall
649 // so networking works correctly.
650
651 err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode, &key );
652 require_noerr( err, exit );
653
654 valueLen = sizeof(DWORD);
655 err = RegQueryValueEx(key, kServiceManageFirewall, 0, &type, (LPBYTE) &value, &valueLen);
656
657 if ((err != ERROR_SUCCESS) || (value == 0))
658 {
659 wchar_t fullPath[ MAX_PATH ];
660 DWORD size;
661
662 // Get a full path to the executable
663
664 size = GetModuleFileNameW( NULL, fullPath, MAX_PATH );
665 err = translate_errno( size > 0, (OSStatus) GetLastError(), kPathErr );
666 require_noerr( err, exit );
667
668 err = mDNSAddToFirewall(fullPath, kServiceFirewallName);
669 require_noerr( err, exit );
670
671 value = 1;
672 err = RegSetValueEx( key, kServiceManageFirewall, 0, REG_DWORD, (const LPBYTE) &value, sizeof( DWORD ) );
673 require_noerr( err, exit );
674 }
675
676 exit:
677
678 if ( key )
679 {
680 RegCloseKey( key );
681 }
682
683 if ( lpService )
684 {
685 free( lpService );
686 }
687
688 if ( sc )
689 {
690 CloseServiceHandle ( sc );
691 }
692
693 return( err );
694 }
695
696
697
698 //===========================================================================================================================
699 // SetServiceInfo
700 //===========================================================================================================================
701
702 static OSStatus SetServiceInfo( SC_HANDLE inSCM, LPCTSTR inServiceName, LPCTSTR inDescription )
703 {
704 OSStatus err;
705 SC_LOCK lock;
706 SC_HANDLE service;
707 SERVICE_DESCRIPTION description;
708 SERVICE_FAILURE_ACTIONS actions;
709 SC_ACTION action;
710 BOOL ok;
711
712 check( inServiceName );
713 check( inDescription );
714
715 lock = NULL;
716 service = NULL;
717
718 // Open the database (if not provided) and lock it to prevent other access while re-configuring.
719
720 if( !inSCM )
721 {
722 inSCM = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
723 err = translate_errno( inSCM, (OSStatus) GetLastError(), kOpenErr );
724 require_noerr( err, exit );
725 }
726
727 lock = LockServiceDatabase( inSCM );
728 err = translate_errno( lock, (OSStatus) GetLastError(), kInUseErr );
729 require_noerr( err, exit );
730
731 // Open a handle to the service.
732
733 service = OpenService( inSCM, inServiceName, SERVICE_CHANGE_CONFIG|SERVICE_START );
734 err = translate_errno( service, (OSStatus) GetLastError(), kNotFoundErr );
735 require_noerr( err, exit );
736
737 // Change the description.
738
739 description.lpDescription = (LPTSTR) inDescription;
740 ok = ChangeServiceConfig2( service, SERVICE_CONFIG_DESCRIPTION, &description );
741 err = translate_errno( ok, (OSStatus) GetLastError(), kParamErr );
742 require_noerr( err, exit );
743
744 actions.dwResetPeriod = INFINITE;
745 actions.lpRebootMsg = NULL;
746 actions.lpCommand = NULL;
747 actions.cActions = 1;
748 actions.lpsaActions = &action;
749 action.Delay = 500;
750 action.Type = SC_ACTION_RESTART;
751
752 ok = ChangeServiceConfig2( service, SERVICE_CONFIG_FAILURE_ACTIONS, &actions );
753 err = translate_errno( ok, (OSStatus) GetLastError(), kParamErr );
754 require_noerr( err, exit );
755
756 err = ERROR_SUCCESS;
757
758 exit:
759 // Close the service and release the lock.
760
761 if( service )
762 {
763 CloseServiceHandle( service );
764 }
765 if( lock )
766 {
767 UnlockServiceDatabase( lock );
768 }
769 return( err );
770 }
771
772 //===========================================================================================================================
773 // ReportStatus
774 //===========================================================================================================================
775
776 static void ReportStatus( int inType, const char *inFormat, ... )
777 {
778 if( !gServiceQuietMode )
779 {
780 va_list args;
781
782 va_start( args, inFormat );
783 if( gServiceEventSource )
784 {
785 char s[ 1024 ];
786 BOOL ok;
787 const char * array[ 1 ];
788
789 vsnprintf( s, sizeof( s ), inFormat, args );
790 array[ 0 ] = s;
791 ok = ReportEventA( gServiceEventSource, (WORD) inType, 0, MDNSRESPONDER_LOG, NULL, 1, 0, array, NULL );
792 check_translated_errno( ok, GetLastError(), kUnknownErr );
793 }
794 else
795 {
796 int n;
797
798 n = vfprintf( stderr, inFormat, args );
799 check( n >= 0 );
800 }
801 va_end( args );
802 }
803 }
804
805 //===========================================================================================================================
806 // RunDirect
807 //===========================================================================================================================
808
809 int RunDirect( int argc, LPTSTR argv[] )
810 {
811 OSStatus err;
812 BOOL initialized;
813 BOOL ok;
814
815 initialized = FALSE;
816
817 err = SetupServiceEvents();
818 require_noerr( err, exit );
819
820 // Install a Console Control Handler to handle things like control-c signals.
821
822 ok = SetConsoleCtrlHandler( ConsoleControlHandler, TRUE );
823 err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
824 require_noerr( err, exit );
825
826 err = ServiceSpecificInitialize( argc, argv );
827 require_noerr( err, exit );
828 initialized = TRUE;
829
830 // Run the service. This does not return until the service quits or is stopped.
831
832 ReportStatus( EVENTLOG_INFORMATION_TYPE, "Running service directly\n" );
833
834 err = ServiceSpecificRun( argc, argv );
835 require_noerr( err, exit );
836
837 // Clean up.
838
839 exit:
840 if( initialized )
841 {
842 ServiceSpecificFinalize( argc, argv );
843 }
844
845 TearDownServiceEvents();
846
847 return( err );
848 }
849
850 #if 0
851 #pragma mark -
852 #endif
853
854 //===========================================================================================================================
855 // ServiceMain
856 //===========================================================================================================================
857
858 static void WINAPI ServiceMain( DWORD argc, LPTSTR argv[] )
859 {
860 OSStatus err;
861 BOOL ok;
862
863 err = SetupServiceEvents();
864 require_noerr( err, exit );
865
866 err = ServiceSetupEventLogging();
867 check_noerr( err );
868
869 err = GetServiceParameters();
870 check_noerr( err );
871
872 // Initialize the service status and register the service control handler with the name of the service.
873
874 gServiceStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
875 gServiceStatus.dwCurrentState = 0;
876 gServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_SHUTDOWN|SERVICE_ACCEPT_POWEREVENT;
877 gServiceStatus.dwWin32ExitCode = NO_ERROR;
878 gServiceStatus.dwServiceSpecificExitCode = NO_ERROR;
879 gServiceStatus.dwCheckPoint = 0;
880 gServiceStatus.dwWaitHint = 0;
881
882 gServiceStatusHandle = RegisterServiceCtrlHandlerEx( argv[ 0 ], ServiceControlHandler, NULL );
883 err = translate_errno( gServiceStatusHandle, (OSStatus) GetLastError(), kInUseErr );
884 require_noerr( err, exit );
885
886 // Mark the service as starting.
887
888 gServiceStatus.dwCurrentState = SERVICE_START_PENDING;
889 gServiceStatus.dwCheckPoint = 0;
890 gServiceStatus.dwWaitHint = 5000; // 5 seconds
891 ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
892 check_translated_errno( ok, GetLastError(), kParamErr );
893
894 // Run the service. This does not return until the service quits or is stopped.
895
896 err = ServiceRun( (int) argc, argv );
897 if( err != kNoErr )
898 {
899 gServiceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
900 gServiceStatus.dwServiceSpecificExitCode = (DWORD) err;
901 }
902
903 // Service-specific work is done so mark the service as stopped.
904
905 gServiceStatus.dwCurrentState = SERVICE_STOPPED;
906 ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
907 check_translated_errno( ok, GetLastError(), kParamErr );
908
909 // Note: The service status handle should not be closed according to Microsoft documentation.
910
911 exit:
912
913 if( gServiceEventSource )
914 {
915 ok = DeregisterEventSource( gServiceEventSource );
916 check_translated_errno( ok, GetLastError(), kUnknownErr );
917 gServiceEventSource = NULL;
918 }
919
920 TearDownServiceEvents();
921 }
922
923 //===========================================================================================================================
924 // ServiceSetupEventLogging
925 //===========================================================================================================================
926
927 static OSStatus ServiceSetupEventLogging( void )
928 {
929 OSStatus err;
930 HKEY key;
931 LPCTSTR s;
932 DWORD typesSupported;
933 TCHAR path[ MAX_PATH ];
934 DWORD n;
935
936 key = NULL;
937
938 // Add/Open source name as a sub-key under the Application key in the EventLog registry key.
939
940 s = TEXT("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\") kServiceName;
941 err = RegCreateKey( HKEY_LOCAL_MACHINE, s, &key );
942 require_noerr( err, exit );
943
944 // Add the name to the EventMessageFile subkey.
945
946 path[ 0 ] = '\0';
947 GetModuleFileName( NULL, path, MAX_PATH );
948 n = (DWORD) ( ( StrLen( path ) + 1 ) * sizeof( TCHAR ) );
949 err = RegSetValueEx( key, TEXT("EventMessageFile"), 0, REG_EXPAND_SZ, (const LPBYTE) path, n );
950 require_noerr( err, exit );
951
952 // Set the supported event types in the TypesSupported subkey.
953
954 typesSupported = 0
955 | EVENTLOG_SUCCESS
956 | EVENTLOG_ERROR_TYPE
957 | EVENTLOG_WARNING_TYPE
958 | EVENTLOG_INFORMATION_TYPE
959 | EVENTLOG_AUDIT_SUCCESS
960 | EVENTLOG_AUDIT_FAILURE;
961 err = RegSetValueEx( key, TEXT("TypesSupported"), 0, REG_DWORD, (const LPBYTE) &typesSupported, sizeof( DWORD ) );
962 require_noerr( err, exit );
963
964 // Set up the event source.
965
966 gServiceEventSource = RegisterEventSource( NULL, kServiceName );
967 err = translate_errno( gServiceEventSource, (OSStatus) GetLastError(), kParamErr );
968 require_noerr( err, exit );
969
970 exit:
971 if( key )
972 {
973 RegCloseKey( key );
974 }
975 return( err );
976 }
977
978
979 //===========================================================================================================================
980 // ServiceControlHandler
981 //===========================================================================================================================
982
983 static DWORD WINAPI ServiceControlHandler( DWORD inControl, DWORD inEventType, LPVOID inEventData, LPVOID inContext )
984 {
985 BOOL setStatus;
986 OSStatus err;
987 BOOL ok;
988
989 DEBUG_UNUSED( inEventData );
990 DEBUG_UNUSED( inContext );
991
992 setStatus = TRUE;
993 switch( inControl )
994 {
995 case SERVICE_CONTROL_STOP:
996 case SERVICE_CONTROL_SHUTDOWN:
997
998 dlog( kDebugLevelInfo, DEBUG_NAME "ServiceControlHandler: SERVICE_CONTROL_STOP|SERVICE_CONTROL_SHUTDOWN\n" );
999
1000 ServiceStop();
1001 setStatus = FALSE;
1002 break;
1003
1004 case SERVICE_CONTROL_POWEREVENT:
1005
1006 if (inEventType == PBT_APMSUSPEND)
1007 {
1008 dlog( kDebugLevelInfo, DEBUG_NAME "ServiceControlHandler: PBT_APMSUSPEND\n" );
1009
1010 if ( gPowerSuspendEvent )
1011 {
1012 ok = SetEvent( gPowerSuspendEvent );
1013 err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
1014 check_noerr( err );
1015
1016 switch ( WaitForSingleObject( gPowerSuspendAckEvent, 5 * 1000 ) )
1017 {
1018 case WAIT_OBJECT_0:
1019 {
1020 // No error
1021 }
1022 break;
1023
1024 case WAIT_TIMEOUT:
1025 {
1026 dlog( kDebugLevelError, DEBUG_NAME "Timed out waiting for acknowledgement of machine sleep\n" );
1027 ReportStatus( EVENTLOG_ERROR_TYPE, "Timed out waiting for acknowledgement of machine sleep" );
1028 }
1029 break;
1030
1031 default:
1032 {
1033 dlog( kDebugLevelError, DEBUG_NAME "Error waiting for acknowledgement of machine sleep: %d", GetLastError() );
1034 ReportStatus( EVENTLOG_ERROR_TYPE, "Error waiting for acknowledgement of machine sleep: %d", GetLastError() );
1035 }
1036 break;
1037 }
1038 }
1039 }
1040 else if (inEventType == PBT_APMRESUMESUSPEND)
1041 {
1042 dlog( kDebugLevelInfo, DEBUG_NAME "ServiceControlHandler: PBT_APMRESUMESUSPEND\n" );
1043
1044 if ( gPowerResumeEvent )
1045 {
1046 ok = SetEvent( gPowerResumeEvent );
1047 err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
1048 check_noerr( err );
1049 }
1050 }
1051
1052 break;
1053
1054 default:
1055 dlog( kDebugLevelNotice, DEBUG_NAME "ServiceControlHandler: event (0x%08X)\n", inControl );
1056 break;
1057 }
1058
1059 if( setStatus && gServiceStatusHandle )
1060 {
1061 ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
1062 check_translated_errno( ok, GetLastError(), kUnknownErr );
1063 }
1064
1065 return NO_ERROR;
1066 }
1067
1068 //===========================================================================================================================
1069 // ServiceRun
1070 //===========================================================================================================================
1071
1072 static OSStatus ServiceRun( int argc, LPTSTR argv[] )
1073 {
1074 OSStatus err;
1075 BOOL initialized;
1076 BOOL ok;
1077
1078 DEBUG_UNUSED( argc );
1079 DEBUG_UNUSED( argv );
1080
1081 initialized = FALSE;
1082
1083 // <rdar://problem/5727548> Make the service as running before we call ServiceSpecificInitialize. We've
1084 // had reports that some machines with McAfee firewall installed cause a problem with iTunes installation.
1085 // We think that the firewall product is interferring with code in ServiceSpecificInitialize. So as a
1086 // simple workaround, we'll mark us as running *before* we call ServiceSpecificInitialize. This will unblock
1087 // any installers that are waiting for our state to change.
1088
1089 gServiceStatus.dwCurrentState = SERVICE_RUNNING;
1090 ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
1091 check_translated_errno( ok, GetLastError(), kParamErr );
1092
1093 // Initialize the service-specific stuff
1094
1095 while ( 1 )
1096 {
1097 DWORD ret;
1098
1099 ReportStatus( EVENTLOG_INFORMATION_TYPE, "Service initializing" );
1100
1101 err = ServiceSpecificInitialize( argc, argv );
1102
1103 if ( !err )
1104 {
1105 ReportStatus( EVENTLOG_INFORMATION_TYPE, "Service initialized" );
1106 break;
1107 }
1108
1109 ReportStatus( EVENTLOG_INFORMATION_TYPE, "Service initialization failed with err %d. Waiting %d seconds to retry...", err, kWaitToRetry );
1110
1111 ret = WaitForSingleObject( gStopEvent, 1000 * kWaitToRetry );
1112
1113 if ( ret == WAIT_OBJECT_0 )
1114 {
1115 ReportStatus( EVENTLOG_INFORMATION_TYPE, "Service received a stop event" );
1116 goto exit;
1117 }
1118 else if ( ret == WAIT_OBJECT_0 + 1 )
1119 {
1120 ReportStatus( EVENTLOG_INFORMATION_TYPE, "Service received a power suspend event" );
1121 }
1122 else if ( ret == WAIT_OBJECT_0 + 2 )
1123 {
1124 ReportStatus( EVENTLOG_INFORMATION_TYPE, "Service received a power resume event" );
1125 }
1126 else if ( ret != WAIT_TIMEOUT )
1127 {
1128 ReportStatus( EVENTLOG_INFORMATION_TYPE, "Service received an error in WaitForSingleObject() : %d, %d", ret, GetLastError() );
1129 goto exit;
1130 }
1131 }
1132
1133 initialized = TRUE;
1134
1135 err = CheckFirewall();
1136 check_noerr( err );
1137
1138 if ( err )
1139 {
1140 gRetryFirewall = TRUE;
1141 }
1142
1143 // Run the service-specific stuff. This does not return until the service quits or is stopped.
1144
1145 ReportStatus( EVENTLOG_INFORMATION_TYPE, "Service started\n" );
1146
1147 err = ServiceSpecificRun( argc, argv );
1148 require_noerr( err, exit );
1149
1150 exit:
1151
1152 // Service stopped. Clean up and we're done.
1153
1154 ReportStatus( EVENTLOG_INFORMATION_TYPE, "Service stopped (%d)\n", err );
1155
1156 if( initialized )
1157 {
1158 ServiceSpecificFinalize( argc, argv );
1159 }
1160
1161 return( err );
1162 }
1163
1164 //===========================================================================================================================
1165 // ServiceStop
1166 //===========================================================================================================================
1167
1168 static void ServiceStop( void )
1169 {
1170 BOOL ok;
1171 OSStatus err;
1172
1173 // Signal the event to cause the service to exit.
1174
1175 if( gServiceStatusHandle )
1176 {
1177 gServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
1178 ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
1179 check_translated_errno( ok, GetLastError(), kParamErr );
1180 }
1181
1182 err = ServiceSpecificStop();
1183 check_noerr( err );
1184 }
1185
1186
1187 #if 0
1188 #pragma mark -
1189 #pragma mark == Service Specific ==
1190 #endif
1191
1192 //===========================================================================================================================
1193 // ServiceSpecificInitialize
1194 //===========================================================================================================================
1195
1196 static OSStatus ServiceSpecificInitialize( int argc, LPTSTR argv[] )
1197 {
1198 OSStatus err;
1199
1200 DEBUG_UNUSED( argc );
1201 DEBUG_UNUSED( argv );
1202
1203 mDNSPlatformMemZero( &gMDNSRecord, sizeof gMDNSRecord);
1204 mDNSPlatformMemZero( &gPlatformStorage, sizeof gPlatformStorage);
1205
1206 gPlatformStorage.reportStatusFunc = ReportStatus;
1207
1208 err = mDNS_Init( &gMDNSRecord, &gPlatformStorage, gRRCache, RR_CACHE_SIZE, mDNS_Init_AdvertiseLocalAddresses, CoreCallback, mDNS_Init_NoInitCallbackContext);
1209 require_noerr( err, exit);
1210
1211 err = SetupNotifications();
1212 check_noerr( err );
1213
1214 err = udsserver_init(mDNSNULL, 0);
1215 require_noerr( err, exit);
1216
1217 SetLLRoute( &gMDNSRecord );
1218
1219 exit:
1220 if( err != kNoErr )
1221 {
1222 ServiceSpecificFinalize( argc, argv );
1223 }
1224 return( err );
1225 }
1226
1227 //===========================================================================================================================
1228 // ServiceSpecificRun
1229 //===========================================================================================================================
1230
1231 static OSStatus ServiceSpecificRun( int argc, LPTSTR argv[] )
1232 {
1233 mDNSBool done = mDNSfalse;
1234 mStatus err = mStatus_NoError;
1235
1236 DEBUG_UNUSED( argc );
1237 DEBUG_UNUSED( argv );
1238
1239 err = SetupInterfaceList( &gMDNSRecord );
1240 check( !err );
1241
1242 err = uDNS_SetupDNSConfig( &gMDNSRecord );
1243 check( !err );
1244
1245 while( !done )
1246 {
1247 static mDNSs32 RepeatedBusy = 0;
1248 mDNSs32 nextTimerEvent;
1249 mStatus err;
1250
1251 // Give the mDNS core a chance to do its work and determine next event time.
1252
1253 nextTimerEvent = udsserver_idle( mDNS_Execute( &gMDNSRecord ) - mDNS_TimeNow( &gMDNSRecord ) );
1254
1255 if ( nextTimerEvent < 0) nextTimerEvent = 0;
1256 else if ( nextTimerEvent > (0x7FFFFFFF / 1000)) nextTimerEvent = 0x7FFFFFFF / mDNSPlatformOneSecond;
1257 else nextTimerEvent = ( nextTimerEvent * 1000) / mDNSPlatformOneSecond;
1258
1259 // Debugging sanity check, to guard against CPU spins
1260
1261 if ( nextTimerEvent > 0 )
1262 {
1263 RepeatedBusy = 0;
1264 }
1265 else
1266 {
1267 nextTimerEvent = 1;
1268
1269 if ( ++RepeatedBusy >= mDNSPlatformOneSecond )
1270 {
1271 ShowTaskSchedulingError( &gMDNSRecord );
1272 RepeatedBusy = 0;
1273 }
1274 }
1275
1276 if ( gMDNSRecord.ShutdownTime )
1277 {
1278 mDNSs32 now = mDNS_TimeNow( &gMDNSRecord );
1279
1280 if ( mDNS_ExitNow( &gMDNSRecord, now ) )
1281 {
1282 mDNS_FinalExit( &gMDNSRecord );
1283 done = TRUE;
1284 break;
1285 }
1286
1287 if ( nextTimerEvent - gMDNSRecord.ShutdownTime >= 0 )
1288 {
1289 nextTimerEvent = gMDNSRecord.ShutdownTime;
1290 }
1291 }
1292
1293 err = mDNSPoll( nextTimerEvent );
1294
1295 if ( err )
1296 {
1297 Sleep( 3 * 1000 );
1298
1299 err = SetupInterfaceList( &gMDNSRecord );
1300 check( !err );
1301
1302 err = uDNS_SetupDNSConfig( &gMDNSRecord );
1303 check( !err );
1304
1305 break;
1306 }
1307 }
1308
1309 return ( err );
1310 }
1311
1312
1313 //===========================================================================================================================
1314 // ServiceSpecificStop
1315 //===========================================================================================================================
1316
1317 static OSStatus ServiceSpecificStop( void )
1318 {
1319 OSStatus err;
1320 BOOL ok;
1321
1322 ok = SetEvent(gStopEvent);
1323 err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
1324 require_noerr( err, exit );
1325
1326 exit:
1327
1328 return( err );
1329 }
1330
1331 //===========================================================================================================================
1332 // ServiceSpecificFinalize
1333 //===========================================================================================================================
1334
1335 static void ServiceSpecificFinalize( int argc, LPTSTR argv[] )
1336 {
1337 DEBUG_UNUSED( argc );
1338 DEBUG_UNUSED( argv );
1339
1340 //
1341 // clean up the notifications
1342 //
1343 TearDownNotifications();
1344
1345 //
1346 // clean up loaded library
1347 //
1348
1349 if( gIPHelperLibraryInstance )
1350 {
1351 gGetIpInterfaceEntryFunctionPtr = NULL;
1352
1353 FreeLibrary( gIPHelperLibraryInstance );
1354 gIPHelperLibraryInstance = NULL;
1355 }
1356 }
1357
1358
1359 //===========================================================================================================================
1360 // SetupServiceEvents
1361 //===========================================================================================================================
1362
1363 mDNSlocal mStatus SetupServiceEvents()
1364 {
1365 mStatus err;
1366
1367 // Stop Event
1368
1369 gStopEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
1370 err = translate_errno( gStopEvent, (mStatus) GetLastError(), kUnknownErr );
1371 require_noerr( err, exit );
1372
1373 exit:
1374
1375 if ( err )
1376 {
1377 TearDownServiceEvents();
1378 }
1379
1380 return err;
1381 }
1382
1383
1384 //===========================================================================================================================
1385 // TearDownServiceNotifications
1386 //===========================================================================================================================
1387
1388 mDNSlocal mStatus TearDownServiceEvents()
1389 {
1390 if ( gStopEvent )
1391 {
1392 CloseHandle( gStopEvent );
1393 gStopEvent = NULL;
1394 }
1395
1396 return mStatus_NoError;
1397 }
1398
1399
1400 //===========================================================================================================================
1401 // SetupNotifications
1402 //===========================================================================================================================
1403
1404 mDNSlocal mStatus SetupNotifications()
1405 {
1406 mStatus err;
1407 SocketRef sock;
1408 unsigned long param;
1409 int inBuffer;
1410 int outBuffer;
1411 DWORD outSize;
1412
1413 require_action( gStopEvent, exit, err = kUnknownErr );
1414 err = mDNSPollRegisterEvent( gStopEvent, StopNotification, NULL );
1415 require_noerr( err, exit );
1416
1417 // Power Suspend
1418
1419 gPowerSuspendEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
1420 err = translate_errno( gPowerSuspendEvent, (mStatus) GetLastError(), kUnknownErr );
1421 require_noerr( err, exit );
1422 err = mDNSPollRegisterEvent( gPowerSuspendEvent, PowerSuspendNotification, NULL );
1423 require_noerr( err, exit );
1424
1425 // Power Suspend Ack
1426
1427 gPowerSuspendAckEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
1428 err = translate_errno( gPowerSuspendAckEvent, ( mStatus ) GetLastError(), kUnknownErr );
1429 require_noerr( err, exit );
1430
1431 // Power Resume
1432
1433 gPowerResumeEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
1434 err = translate_errno( gPowerResumeEvent, (mStatus) GetLastError(), kUnknownErr );
1435 require_noerr( err, exit );
1436 err = mDNSPollRegisterEvent( gPowerResumeEvent, PowerResumeNotification, NULL );
1437 require_noerr( err, exit );
1438
1439 // Register to listen for address list changes.
1440
1441 sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
1442 err = translate_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
1443 require_noerr( err, exit );
1444 gInterfaceListChangedSocket = sock;
1445
1446 // Make the socket non-blocking so the WSAIoctl returns immediately with WSAEWOULDBLOCK. It will set the event
1447 // when a change to the interface list is detected.
1448
1449 param = 1;
1450 err = ioctlsocket( sock, FIONBIO, &param );
1451 err = translate_errno( err == 0, errno_compat(), kUnknownErr );
1452 require_noerr( err, exit );
1453
1454 inBuffer = 0;
1455 outBuffer = 0;
1456 err = WSAIoctl( sock, SIO_ADDRESS_LIST_CHANGE, &inBuffer, 0, &outBuffer, 0, &outSize, NULL, NULL );
1457 if( err < 0 )
1458 {
1459 check( errno_compat() == WSAEWOULDBLOCK );
1460 }
1461
1462 err = mDNSPollRegisterSocket( sock, FD_ADDRESS_LIST_CHANGE, InterfaceListNotification, NULL );
1463 require_noerr( err, exit );
1464
1465 gDescChangedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
1466 err = translate_errno( gDescChangedEvent, (mStatus) GetLastError(), kUnknownErr );
1467 require_noerr( err, exit );
1468
1469 err = RegOpenKeyEx( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\parameters"), 0, KEY_READ, &gDescKey);
1470 check_translated_errno( err == 0, errno_compat(), kNameErr );
1471
1472 if ( gDescKey != NULL )
1473 {
1474 err = RegNotifyChangeKeyValue( gDescKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET, gDescChangedEvent, TRUE);
1475 require_noerr( err, exit );
1476 }
1477
1478 err = mDNSPollRegisterEvent( gDescChangedEvent, ComputerDescriptionNotification, NULL );
1479 require_noerr( err, exit );
1480
1481 // This will catch all changes to tcp/ip networking, including changes to the domain search list
1482
1483 gTcpipChangedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
1484 err = translate_errno( gTcpipChangedEvent, (mStatus) GetLastError(), kUnknownErr );
1485 require_noerr( err, exit );
1486 err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), &gTcpipKey );
1487 require_noerr( err, exit );
1488 err = RegNotifyChangeKeyValue( gTcpipKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gTcpipChangedEvent, TRUE);
1489 require_noerr( err, exit );
1490 err = mDNSPollRegisterEvent( gTcpipChangedEvent, TCPChangedNotification, NULL );
1491 require_noerr( err, exit );
1492
1493 // This will catch all changes to ddns configuration
1494
1495 gDdnsChangedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
1496 err = translate_errno( gDdnsChangedEvent, (mStatus) GetLastError(), kUnknownErr );
1497 require_noerr( err, exit );
1498 err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode TEXT("\\DynDNS\\Setup"), &gDdnsKey );
1499 require_noerr( err, exit );
1500 err = RegNotifyChangeKeyValue( gDdnsKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gDdnsChangedEvent, TRUE);
1501 require_noerr( err, exit );
1502 err = mDNSPollRegisterEvent( gDdnsChangedEvent, DDNSChangedNotification, NULL );
1503 require_noerr( err, exit );
1504
1505 // This will catch all changes to file sharing
1506
1507 gFileSharingChangedEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
1508 err = translate_errno( gFileSharingChangedEvent, (mStatus) GetLastError(), kUnknownErr );
1509 require_noerr( err, exit );
1510
1511 err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\Shares"), &gFileSharingKey );
1512
1513 // Just to make sure that initialization doesn't fail on some old OS
1514 // that doesn't have this key, we'll only add the notification if
1515 // the key exists.
1516
1517 if ( !err )
1518 {
1519 err = RegNotifyChangeKeyValue( gFileSharingKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gFileSharingChangedEvent, TRUE);
1520 require_noerr( err, exit );
1521 err = mDNSPollRegisterEvent( gFileSharingChangedEvent, FileSharingChangedNotification, NULL );
1522 require_noerr( err, exit );
1523 }
1524 else
1525 {
1526 err = mStatus_NoError;
1527 }
1528
1529 // This will catch changes to the Windows firewall
1530
1531 gFirewallChangedEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
1532 err = translate_errno( gFirewallChangedEvent, (mStatus) GetLastError(), kUnknownErr );
1533 require_noerr( err, exit );
1534
1535 // Just to make sure that initialization doesn't fail on some old OS
1536 // that doesn't have this key, we'll only add the notification if
1537 // the key exists.
1538
1539 err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\SharedAccess\\Parameters\\FirewallPolicy\\FirewallRules"), &gFirewallKey );
1540
1541 if ( !err )
1542 {
1543 err = RegNotifyChangeKeyValue( gFirewallKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gFirewallChangedEvent, TRUE);
1544 require_noerr( err, exit );
1545 err = mDNSPollRegisterEvent( gFirewallChangedEvent, FirewallChangedNotification, NULL );
1546 require_noerr( err, exit );
1547 }
1548 else
1549 {
1550 err = mStatus_NoError;
1551 }
1552
1553 // This will catch all changes to advertised services configuration
1554
1555 gAdvertisedServicesChangedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
1556 err = translate_errno( gAdvertisedServicesChangedEvent, (mStatus) GetLastError(), kUnknownErr );
1557 require_noerr( err, exit );
1558 err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode TEXT("\\Services"), &gAdvertisedServicesKey );
1559 require_noerr( err, exit );
1560 err = RegNotifyChangeKeyValue( gAdvertisedServicesKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gAdvertisedServicesChangedEvent, TRUE);
1561 require_noerr( err, exit );
1562 err = mDNSPollRegisterEvent( gAdvertisedServicesChangedEvent, AdvertisedServicesChangedNotification, NULL );
1563 require_noerr( err, exit );
1564
1565 // SPSWakeup timer
1566
1567 gSPSWakeupEvent = CreateWaitableTimer( NULL, FALSE, NULL );
1568 err = translate_errno( gSPSWakeupEvent, (mStatus) GetLastError(), kUnknownErr );
1569 require_noerr( err, exit );
1570 err = mDNSPollRegisterEvent( gSPSWakeupEvent, SPSWakeupNotification, NULL );
1571 require_noerr( err, exit );
1572
1573 // SPSSleep timer
1574
1575 gSPSSleepEvent = CreateWaitableTimer( NULL, FALSE, NULL );
1576 err = translate_errno( gSPSSleepEvent, (mStatus) GetLastError(), kUnknownErr );
1577 require_noerr( err, exit );
1578 err = mDNSPollRegisterEvent( gSPSSleepEvent, SPSSleepNotification, NULL );
1579 require_noerr( err, exit );
1580
1581 exit:
1582 if( err )
1583 {
1584 TearDownNotifications();
1585 }
1586 return( err );
1587 }
1588
1589 //===========================================================================================================================
1590 // TearDownNotifications
1591 //===========================================================================================================================
1592
1593 mDNSlocal mStatus TearDownNotifications()
1594 {
1595 if( IsValidSocket( gInterfaceListChangedSocket ) )
1596 {
1597 mDNSPollUnregisterSocket( gInterfaceListChangedSocket );
1598
1599 close_compat( gInterfaceListChangedSocket );
1600 gInterfaceListChangedSocket = kInvalidSocketRef;
1601 }
1602
1603 if ( gDescChangedEvent != NULL )
1604 {
1605 mDNSPollUnregisterEvent( gDescChangedEvent );
1606 CloseHandle( gDescChangedEvent );
1607 gDescChangedEvent = NULL;
1608 }
1609
1610 if ( gDescKey != NULL )
1611 {
1612 RegCloseKey( gDescKey );
1613 gDescKey = NULL;
1614 }
1615
1616 if ( gTcpipChangedEvent != NULL )
1617 {
1618 mDNSPollUnregisterEvent( gTcpipChangedEvent );
1619 CloseHandle( gTcpipChangedEvent );
1620 gTcpipChangedEvent = NULL;
1621 }
1622
1623 if ( gDdnsChangedEvent != NULL )
1624 {
1625 mDNSPollUnregisterEvent( gDdnsChangedEvent );
1626 CloseHandle( gDdnsChangedEvent );
1627 gDdnsChangedEvent = NULL;
1628 }
1629
1630 if ( gDdnsKey != NULL )
1631 {
1632 RegCloseKey( gDdnsKey );
1633 gDdnsKey = NULL;
1634 }
1635
1636 if ( gFileSharingChangedEvent != NULL )
1637 {
1638 mDNSPollUnregisterEvent( gFileSharingChangedEvent );
1639 CloseHandle( gFileSharingChangedEvent );
1640 gFileSharingChangedEvent = NULL;
1641 }
1642
1643 if ( gFileSharingKey != NULL )
1644 {
1645 RegCloseKey( gFileSharingKey );
1646 gFileSharingKey = NULL;
1647 }
1648
1649 if ( gFirewallChangedEvent != NULL )
1650 {
1651 mDNSPollUnregisterEvent( gFirewallChangedEvent );
1652 CloseHandle( gFirewallChangedEvent );
1653 gFirewallChangedEvent = NULL;
1654 }
1655
1656 if ( gFirewallKey != NULL )
1657 {
1658 RegCloseKey( gFirewallKey );
1659 gFirewallKey = NULL;
1660 }
1661
1662 if ( gAdvertisedServicesChangedEvent != NULL )
1663 {
1664 mDNSPollUnregisterEvent( gAdvertisedServicesChangedEvent );
1665 CloseHandle( gAdvertisedServicesChangedEvent );
1666 gAdvertisedServicesChangedEvent = NULL;
1667 }
1668
1669 if ( gAdvertisedServicesKey != NULL )
1670 {
1671 RegCloseKey( gAdvertisedServicesKey );
1672 gAdvertisedServicesKey = NULL;
1673 }
1674
1675 if ( gSPSWakeupEvent )
1676 {
1677 mDNSPollUnregisterEvent( gSPSWakeupEvent );
1678 CloseHandle( gSPSWakeupEvent );
1679 gSPSWakeupEvent = NULL;
1680 }
1681
1682 if ( gSPSSleepEvent )
1683 {
1684 mDNSPollUnregisterEvent( gSPSSleepEvent );
1685 CloseHandle( gSPSSleepEvent );
1686 gSPSSleepEvent = NULL;
1687 }
1688
1689 if ( gPowerResumeEvent )
1690 {
1691 mDNSPollUnregisterEvent( gPowerResumeEvent );
1692 CloseHandle( gPowerResumeEvent );
1693 gPowerResumeEvent = NULL;
1694 }
1695
1696 if ( gPowerSuspendAckEvent )
1697 {
1698 CloseHandle( gPowerSuspendAckEvent );
1699 gPowerSuspendAckEvent = NULL;
1700 }
1701
1702 if ( gPowerSuspendEvent )
1703 {
1704 mDNSPollUnregisterEvent( gPowerSuspendEvent );
1705 CloseHandle( gPowerSuspendEvent );
1706 gPowerSuspendEvent = NULL;
1707 }
1708
1709 if ( gStopEvent )
1710 {
1711 mDNSPollUnregisterEvent( gStopEvent );
1712 }
1713
1714 return( mStatus_NoError );
1715 }
1716
1717
1718 mDNSlocal void CALLBACK
1719 StopNotification( HANDLE event, void *context )
1720 {
1721 DEBUG_UNUSED( event );
1722 DEBUG_UNUSED( context );
1723
1724 dlog( kDebugLevelVerbose, DEBUG_NAME "stopping...\n" );
1725 udsserver_exit();
1726 mDNS_StartExit( &gMDNSRecord );
1727 }
1728
1729
1730 mDNSlocal void CALLBACK
1731 PowerSuspendNotification( HANDLE event, void * context )
1732 {
1733 LARGE_INTEGER timeout;
1734 BOOL ok;
1735
1736 DEBUG_UNUSED( event );
1737 DEBUG_UNUSED( context );
1738
1739 dlog( kDebugLevelInfo, DEBUG_NAME "PowerSuspendNotification\n" );
1740
1741 gMDNSRecord.SystemWakeOnLANEnabled = SystemWakeForNetworkAccess( &timeout );
1742
1743 if ( gMDNSRecord.SystemWakeOnLANEnabled )
1744 {
1745 ok = SetWaitableTimer( gSPSWakeupEvent, &timeout, 0, NULL, NULL, TRUE );
1746 check( ok );
1747 }
1748
1749 mDNSCoreMachineSleep(&gMDNSRecord, TRUE);
1750
1751 ok = SetEvent( gPowerSuspendAckEvent );
1752
1753 if ( !ok )
1754 {
1755 dlog( kDebugLevelError, DEBUG_NAME "PowerSuspendNotification: error while setting acknowledgement: %d", GetLastError() );
1756 ReportStatus( EVENTLOG_ERROR_TYPE, "PowerSuspendNotification: error while setting acknowledgement: %d", GetLastError() );
1757 }
1758 }
1759
1760
1761 mDNSlocal void CALLBACK
1762 PowerResumeNotification( HANDLE event, void * context )
1763 {
1764 DEBUG_UNUSED( event );
1765 DEBUG_UNUSED( context );
1766
1767 dlog( kDebugLevelInfo, DEBUG_NAME "PowerResumeNotification\n" );
1768
1769 if ( gSPSWakeupEvent )
1770 {
1771 CancelWaitableTimer( gSPSWakeupEvent );
1772 }
1773
1774 if ( gSPSSleepEvent )
1775 {
1776 CancelWaitableTimer( gSPSSleepEvent );
1777 }
1778
1779 mDNSCoreMachineSleep(&gMDNSRecord, FALSE);
1780 }
1781
1782
1783
1784 mDNSlocal void CALLBACK
1785 InterfaceListNotification( SOCKET socket, LPWSANETWORKEVENTS event, void *context )
1786 {
1787 int inBuffer;
1788 int outBuffer;
1789 DWORD outSize;
1790 int err;
1791
1792 DEBUG_UNUSED( socket );
1793 DEBUG_UNUSED( event );
1794 DEBUG_UNUSED( context );
1795
1796 // It would be nice to come up with a more elegant solution to this, but it seems that
1797 // GetAdaptersAddresses doesn't always stay in sync after network changed events. So as
1798 // as a simple workaround, we'll pause for a couple of seconds before processing the change.
1799
1800 // We arrived at 2 secs by trial and error. We could reproduce the problem after sleeping
1801 // for 500 msec and 750 msec, but couldn't after sleeping for 1 sec. We added another
1802 // second on top of that to account for machine load or some other exigency.
1803
1804 Sleep( 2000 );
1805
1806 // Interface list changed event. Break out of the inner loop to re-setup the wait list.
1807
1808 InterfaceListDidChange( &gMDNSRecord );
1809
1810 // reset the event handler
1811 inBuffer = 0;
1812 outBuffer = 0;
1813 err = WSAIoctl( gInterfaceListChangedSocket, SIO_ADDRESS_LIST_CHANGE, &inBuffer, 0, &outBuffer, 0, &outSize, NULL, NULL );
1814 if( err < 0 )
1815 {
1816 check( errno_compat() == WSAEWOULDBLOCK );
1817 }
1818 }
1819
1820
1821 mDNSlocal void CALLBACK
1822 ComputerDescriptionNotification( HANDLE event, void *context )
1823 {
1824 // The computer description might have changed
1825
1826 DEBUG_UNUSED( event );
1827 DEBUG_UNUSED( context );
1828
1829 ComputerDescriptionDidChange( &gMDNSRecord );
1830 udsserver_handle_configchange( &gMDNSRecord );
1831
1832 // and reset the event handler
1833 if ( ( gDescKey != NULL ) && ( gDescChangedEvent != NULL ) )
1834 {
1835 int err = RegNotifyChangeKeyValue( gDescKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET, gDescChangedEvent, TRUE);
1836 check_noerr( err );
1837 }
1838 }
1839
1840
1841 mDNSlocal void CALLBACK
1842 TCPChangedNotification( HANDLE event, void *context )
1843 {
1844 // The TCP/IP might have changed
1845
1846 DEBUG_UNUSED( event );
1847 DEBUG_UNUSED( context );
1848
1849 TCPIPConfigDidChange( &gMDNSRecord );
1850 udsserver_handle_configchange( &gMDNSRecord );
1851
1852 // and reset the event handler
1853
1854 if ( ( gTcpipKey != NULL ) && ( gTcpipChangedEvent ) )
1855 {
1856 int err = RegNotifyChangeKeyValue( gTcpipKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gTcpipChangedEvent, TRUE );
1857 check_noerr( err );
1858 }
1859 }
1860
1861
1862 mDNSlocal void CALLBACK
1863 DDNSChangedNotification( HANDLE event, void *context )
1864 {
1865 // The DynDNS config might have changed
1866
1867 DEBUG_UNUSED( event );
1868 DEBUG_UNUSED( context );
1869
1870 DynDNSConfigDidChange( &gMDNSRecord );
1871 udsserver_handle_configchange( &gMDNSRecord );
1872
1873 // and reset the event handler
1874
1875 if ((gDdnsKey != NULL) && (gDdnsChangedEvent))
1876 {
1877 int err = RegNotifyChangeKeyValue(gDdnsKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gDdnsChangedEvent, TRUE);
1878 check_noerr( err );
1879 }
1880 }
1881
1882
1883 mDNSlocal void CALLBACK
1884 FileSharingChangedNotification( HANDLE event, void *context )
1885 {
1886 // File sharing changed
1887
1888 DEBUG_UNUSED( event );
1889 DEBUG_UNUSED( context );
1890
1891 FileSharingDidChange( &gMDNSRecord );
1892
1893 // and reset the event handler
1894
1895 if ((gFileSharingKey != NULL) && (gFileSharingChangedEvent))
1896 {
1897 int err = RegNotifyChangeKeyValue(gFileSharingKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gFileSharingChangedEvent, TRUE);
1898 check_noerr( err );
1899 }
1900 }
1901
1902
1903 mDNSlocal void CALLBACK
1904 FirewallChangedNotification( HANDLE event, void *context )
1905 {
1906 // Firewall configuration changed
1907
1908 DEBUG_UNUSED( event );
1909 DEBUG_UNUSED( context );
1910
1911 FirewallDidChange( &gMDNSRecord );
1912
1913 // and reset the event handler
1914
1915 if ((gFirewallKey != NULL) && (gFirewallChangedEvent))
1916 {
1917 int err = RegNotifyChangeKeyValue(gFirewallKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gFirewallChangedEvent, TRUE);
1918 check_noerr( err );
1919 }
1920 }
1921
1922
1923 mDNSlocal void CALLBACK
1924 AdvertisedServicesChangedNotification( HANDLE event, void *context )
1925 {
1926 // Ultimately we'll want to manage multiple services, but right now the only service
1927 // we'll be managing is SMB.
1928
1929 DEBUG_UNUSED( event );
1930 DEBUG_UNUSED( context );
1931
1932 FileSharingDidChange( &gMDNSRecord );
1933
1934 // and reset the event handler
1935
1936 if ( ( gAdvertisedServicesKey != NULL ) && ( gAdvertisedServicesChangedEvent ) )
1937 {
1938 int err = RegNotifyChangeKeyValue(gAdvertisedServicesKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gAdvertisedServicesChangedEvent, TRUE);
1939 check_noerr( err );
1940 }
1941 }
1942
1943
1944 mDNSlocal void CALLBACK
1945 SPSWakeupNotification( HANDLE event, void *context )
1946 {
1947 LARGE_INTEGER timeout;
1948
1949 DEBUG_UNUSED( event );
1950 DEBUG_UNUSED( context );
1951
1952 ReportStatus( EVENTLOG_INFORMATION_TYPE, "Maintenance wake" );
1953
1954 timeout.QuadPart = kSPSMaintenanceWakePeriod;
1955 timeout.QuadPart *= kSecondsTo100NSUnits;
1956
1957 SetWaitableTimer( gSPSSleepEvent, &timeout, 0, NULL, NULL, TRUE );
1958 }
1959
1960
1961 mDNSlocal void CALLBACK
1962 SPSSleepNotification( HANDLE event, void *context )
1963 {
1964 DEBUG_UNUSED( event );
1965 DEBUG_UNUSED( context );
1966
1967 ReportStatus( EVENTLOG_INFORMATION_TYPE, "Returning to sleep after maintenance wake" );
1968
1969 // Calling SetSuspendState() doesn't invoke our sleep handlers, so we'll
1970 // call HandlePowerSuspend() explicity. This will reset the
1971 // maintenance wake timers.
1972
1973 PowerSuspendNotification( gPowerSuspendEvent, NULL );
1974 SetSuspendState( FALSE, FALSE, FALSE );
1975 }
1976
1977
1978 //===========================================================================================================================
1979 // CoreCallback
1980 //===========================================================================================================================
1981
1982 static void
1983 CoreCallback(mDNS * const inMDNS, mStatus status)
1984 {
1985 if (status == mStatus_ConfigChanged)
1986 {
1987 SetLLRoute( inMDNS );
1988 }
1989 }
1990
1991
1992 //===========================================================================================================================
1993 // UDSAcceptNotification
1994 //===========================================================================================================================
1995
1996 mDNSlocal void CALLBACK
1997 UDSAcceptNotification( SOCKET sock, LPWSANETWORKEVENTS event, void *context )
1998 {
1999 ( void ) sock;
2000 ( void ) event;
2001 ( void ) context;
2002
2003 if ( gUDSCallback )
2004 {
2005 gUDSCallback( ( int ) gUDSSocket, 0, context );
2006 }
2007 }
2008
2009
2010 //===========================================================================================================================
2011 // UDSReadNotification
2012 //===========================================================================================================================
2013
2014 mDNSlocal void CALLBACK
2015 UDSReadNotification( SOCKET sock, LPWSANETWORKEVENTS event, void *context )
2016 {
2017 TCPSocket *tcpSock = ( TCPSocket* ) context;
2018
2019 ( void ) sock;
2020 ( void ) event;
2021
2022 if ( tcpSock )
2023 {
2024 tcpSock->userCallback( ( int ) tcpSock->fd, 0, tcpSock->userContext );
2025 }
2026 }
2027
2028
2029 //===========================================================================================================================
2030 // udsSupportAddFDToEventLoop
2031 //===========================================================================================================================
2032
2033 mStatus
2034 udsSupportAddFDToEventLoop( SocketRef fd, udsEventCallback callback, void *context, void **platform_data)
2035 {
2036 mStatus err = mStatus_NoError;
2037
2038 // We are using some knowledge of what is being passed to us here. If the fd is a listen socket,
2039 // then the "context" parameter is NULL. If it is an actual read/write socket, then the "context"
2040 // parameter is not null.
2041
2042 if ( context )
2043 {
2044 TCPSocket * sock;
2045
2046 sock = malloc( sizeof( TCPSocket ) );
2047 require_action( sock, exit, err = mStatus_NoMemoryErr );
2048 mDNSPlatformMemZero( sock, sizeof( TCPSocket ) );
2049
2050 sock->fd = (SOCKET) fd;
2051 sock->userCallback = callback;
2052 sock->userContext = context;
2053 sock->m = &gMDNSRecord;
2054
2055 *platform_data = sock;
2056
2057 err = mDNSPollRegisterSocket( sock->fd, FD_READ | FD_CLOSE, UDSReadNotification, sock );
2058 require_noerr( err, exit );
2059 }
2060 else
2061 {
2062 gUDSSocket = fd;
2063 gUDSCallback = callback;
2064
2065 err = mDNSPollRegisterSocket( gUDSSocket, FD_ACCEPT | FD_CLOSE, UDSAcceptNotification, NULL );
2066 require_noerr( err, exit );
2067 }
2068
2069 exit:
2070
2071 return err;
2072 }
2073
2074
2075 int
2076 udsSupportReadFD( SocketRef fd, char *buf, int len, int flags, void *platform_data )
2077 {
2078 TCPSocket * sock;
2079 mDNSBool closed;
2080 int ret;
2081
2082 ( void ) flags;
2083
2084 sock = ( TCPSocket* ) platform_data;
2085 require_action( sock, exit, ret = -1 );
2086 require_action( sock->fd == fd, exit, ret = -1 );
2087
2088 ret = mDNSPlatformReadTCP( sock, buf, len, &closed );
2089
2090 if ( closed )
2091 {
2092 ret = 0;
2093 }
2094 else if ( !ret && ( WSAGetLastError() == WSAEWOULDBLOCK ) )
2095 {
2096 // mDNSPlatformReadTCP will return 0 if it gets WSAEWOULDBLOCK, but
2097 // that caller of this routine interprets that as close connection.
2098 // We'll fix that by returning -1 in that case.
2099
2100 ret = -1;
2101 }
2102
2103 exit:
2104
2105 return ret;
2106 }
2107
2108
2109 mStatus
2110 udsSupportRemoveFDFromEventLoop( SocketRef fd, void *platform_data) // Note: This also CLOSES the socket
2111 {
2112 mStatus err = kNoErr;
2113
2114 mDNSPollUnregisterSocket( fd );
2115
2116 if ( platform_data != NULL )
2117 {
2118 TCPSocket * sock;
2119
2120 dlog( kDebugLevelInfo, DEBUG_NAME "session closed\n" );
2121 sock = ( TCPSocket* ) platform_data;
2122 check( sock->fd == fd );
2123 mDNSPlatformTCPCloseConnection( sock );
2124 }
2125
2126 return err;
2127 }
2128
2129
2130 mDNSexport void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay)
2131 {
2132 (void)m;
2133 (void)delay;
2134 // No-op, for now
2135 }
2136
2137
2138 //===========================================================================================================================
2139 // SystemWakeForNetworkAccess
2140 //===========================================================================================================================
2141
2142 mDNSu8
2143 SystemWakeForNetworkAccess( LARGE_INTEGER * timeout )
2144 {
2145 HKEY key = NULL;
2146 DWORD dwSize;
2147 DWORD enabled;
2148 mDNSu8 ok;
2149 SYSTEM_POWER_STATUS powerStatus;
2150 time_t startTime;
2151 time_t nextWakeupTime;
2152 int delta;
2153 DWORD err;
2154
2155 dlog( kDebugLevelInfo, DEBUG_NAME "SystemWakeForNetworkAccess\n" );
2156
2157 // Make sure we have a timer
2158
2159 require_action( gSPSWakeupEvent != NULL, exit, ok = FALSE );
2160 require_action( gSPSSleepEvent != NULL, exit, ok = FALSE );
2161
2162 // Make sure the user enabled bonjour sleep proxy client
2163
2164 err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Power Management", &key );
2165 require_action( !err, exit, ok = FALSE );
2166 dwSize = sizeof( DWORD );
2167 err = RegQueryValueEx( key, L"Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize );
2168 require_action( !err, exit, ok = FALSE );
2169 require_action( enabled, exit, ok = FALSE );
2170
2171 // Make sure machine is on AC power
2172
2173 ok = ( mDNSu8 ) GetSystemPowerStatus( &powerStatus );
2174 require_action( ok, exit, ok = FALSE );
2175 require_action( powerStatus.ACLineStatus == AC_LINE_ONLINE, exit, ok = FALSE );
2176
2177 // Now make sure we have a network interface that does wake-on-lan
2178
2179 ok = ( mDNSu8 ) IsWOMPEnabled( &gMDNSRecord );
2180 require_action( ok, exit, ok = FALSE );
2181
2182 // Now make sure we have advertised services. Doesn't make sense to
2183 // enable sleep proxy if we have no multicast services that could
2184 // potentially wake us up.
2185
2186 ok = ( mDNSu8 ) mDNSCoreHaveAdvertisedMulticastServices( &gMDNSRecord );
2187 require_action( ok, exit, ok = FALSE );
2188
2189 // Calculate next wake up time
2190
2191 startTime = time( NULL ); // Seconds since midnight January 1, 1970
2192 nextWakeupTime = startTime + ( 120 * 60 ); // 2 hours later
2193
2194 if ( gMDNSRecord.p->nextDHCPLeaseExpires < nextWakeupTime )
2195 {
2196 nextWakeupTime = gMDNSRecord.p->nextDHCPLeaseExpires;
2197 }
2198
2199 // Finally calculate the next relative wakeup time
2200
2201 delta = ( int )( ( ( double )( nextWakeupTime - startTime ) ) * 0.9 );
2202 ReportStatus( EVENTLOG_INFORMATION_TYPE, "enabling sleep proxy client with next maintenance wake in %d seconds", delta );
2203
2204 // Convert seconds to 100 nanosecond units expected by SetWaitableTimer
2205
2206 timeout->QuadPart = -delta;
2207 timeout->QuadPart *= kSecondsTo100NSUnits;
2208
2209 ok = TRUE;
2210
2211 exit:
2212
2213 if ( key )
2214 {
2215 RegCloseKey( key );
2216 }
2217
2218 return ok;
2219 }
2220
2221
2222 //===========================================================================================================================
2223 // HaveRoute
2224 //===========================================================================================================================
2225
2226 static bool
2227 HaveRoute( PMIB_IPFORWARDROW rowExtant, unsigned long addr, unsigned long metric )
2228 {
2229 PMIB_IPFORWARDTABLE pIpForwardTable = NULL;
2230 DWORD dwSize = 0;
2231 BOOL bOrder = FALSE;
2232 OSStatus err;
2233 bool found = false;
2234 unsigned long int i;
2235
2236 //
2237 // Find out how big our buffer needs to be.
2238 //
2239 err = GetIpForwardTable(NULL, &dwSize, bOrder);
2240 require_action( err == ERROR_INSUFFICIENT_BUFFER, exit, err = kUnknownErr );
2241
2242 //
2243 // Allocate the memory for the table
2244 //
2245 pIpForwardTable = (PMIB_IPFORWARDTABLE) malloc( dwSize );
2246 require_action( pIpForwardTable, exit, err = kNoMemoryErr );
2247
2248 //
2249 // Now get the table.
2250 //
2251 err = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder);
2252 require_noerr( err, exit );
2253
2254 //
2255 // Search for the row in the table we want.
2256 //
2257 for ( i = 0; i < pIpForwardTable->dwNumEntries; i++)
2258 {
2259 if ( ( pIpForwardTable->table[i].dwForwardDest == addr ) && ( !metric || ( pIpForwardTable->table[i].dwForwardMetric1 == metric ) ) )
2260 {
2261 memcpy( rowExtant, &(pIpForwardTable->table[i]), sizeof(*rowExtant) );
2262 found = true;
2263 break;
2264 }
2265 }
2266
2267 exit:
2268
2269 if ( pIpForwardTable != NULL )
2270 {
2271 free(pIpForwardTable);
2272 }
2273
2274 return found;
2275 }
2276
2277
2278 //===========================================================================================================================
2279 // IsValidAddress
2280 //===========================================================================================================================
2281
2282 static bool
2283 IsValidAddress( const char * addr )
2284 {
2285 return ( addr && ( strcmp( addr, "0.0.0.0" ) != 0 ) ) ? true : false;
2286 }
2287
2288
2289 //===========================================================================================================================
2290 // GetAdditionalMetric
2291 //===========================================================================================================================
2292
2293 static ULONG
2294 GetAdditionalMetric( DWORD ifIndex )
2295 {
2296 ULONG metric = 0;
2297
2298 if( !gIPHelperLibraryInstance )
2299 {
2300 gIPHelperLibraryInstance = LoadLibrary( TEXT( "Iphlpapi" ) );
2301
2302 gGetIpInterfaceEntryFunctionPtr =
2303 (GetIpInterfaceEntryFunctionPtr) GetProcAddress( gIPHelperLibraryInstance, "GetIpInterfaceEntry" );
2304
2305 if( !gGetIpInterfaceEntryFunctionPtr )
2306 {
2307 BOOL ok;
2308
2309 ok = FreeLibrary( gIPHelperLibraryInstance );
2310 check_translated_errno( ok, GetLastError(), kUnknownErr );
2311 gIPHelperLibraryInstance = NULL;
2312 }
2313 }
2314
2315 if ( gGetIpInterfaceEntryFunctionPtr )
2316 {
2317 MIB_IPINTERFACE_ROW row;
2318 DWORD err;
2319
2320 ZeroMemory( &row, sizeof( MIB_IPINTERFACE_ROW ) );
2321 row.Family = AF_INET;
2322 row.InterfaceIndex = ifIndex;
2323 err = gGetIpInterfaceEntryFunctionPtr( &row );
2324 require_noerr( err, exit );
2325 metric = row.Metric + 256;
2326 }
2327
2328 exit:
2329
2330 return metric;
2331 }
2332
2333
2334 //===========================================================================================================================
2335 // SetLLRoute
2336 //===========================================================================================================================
2337
2338 static OSStatus
2339 SetLLRoute( mDNS * const inMDNS )
2340 {
2341 OSStatus err = kNoErr;
2342
2343 DEBUG_UNUSED( inMDNS );
2344
2345 //
2346 // <rdar://problem/4096464> Don't call SetLLRoute on loopback
2347 // <rdar://problem/6885843> Default route on Windows 7 breaks network connectivity
2348 //
2349 // Don't mess w/ the routing table on Vista and later OSes, as
2350 // they have a permanent route to link-local addresses. Otherwise,
2351 // set a route to link local addresses (169.254.0.0)
2352 //
2353 if ( ( inMDNS->p->osMajorVersion < 6 ) && gServiceManageLLRouting && !gPlatformStorage.registeredLoopback4 )
2354 {
2355 DWORD ifIndex;
2356 MIB_IPFORWARDROW rowExtant;
2357 bool addRoute;
2358 MIB_IPFORWARDROW row;
2359
2360 ZeroMemory(&row, sizeof(row));
2361
2362 err = GetRouteDestination(&ifIndex, &row.dwForwardNextHop);
2363 require_noerr( err, exit );
2364 row.dwForwardDest = inet_addr(kLLNetworkAddr);
2365 row.dwForwardIfIndex = ifIndex;
2366 row.dwForwardMask = inet_addr(kLLNetworkAddrMask);
2367 row.dwForwardType = 3;
2368 row.dwForwardProto = MIB_IPPROTO_NETMGMT;
2369 row.dwForwardAge = 0;
2370 row.dwForwardPolicy = 0;
2371 row.dwForwardMetric1 = 20 + GetAdditionalMetric( ifIndex );
2372 row.dwForwardMetric2 = (DWORD) - 1;
2373 row.dwForwardMetric3 = (DWORD) - 1;
2374 row.dwForwardMetric4 = (DWORD) - 1;
2375 row.dwForwardMetric5 = (DWORD) - 1;
2376
2377 addRoute = true;
2378
2379 //
2380 // check to make sure we don't already have a route
2381 //
2382 if ( HaveRoute( &rowExtant, inet_addr( kLLNetworkAddr ), 0 ) )
2383 {
2384 //
2385 // set the age to 0 so that we can do a memcmp.
2386 //
2387 rowExtant.dwForwardAge = 0;
2388
2389 //
2390 // check to see if this route is the same as our route
2391 //
2392 if (memcmp(&row, &rowExtant, sizeof(row)) != 0)
2393 {
2394 //
2395 // if it isn't then delete this entry
2396 //
2397 DeleteIpForwardEntry(&rowExtant);
2398 }
2399 else
2400 {
2401 //
2402 // else it is, so we don't want to create another route
2403 //
2404 addRoute = false;
2405 }
2406 }
2407
2408 if (addRoute && row.dwForwardNextHop)
2409 {
2410 err = CreateIpForwardEntry(&row);
2411 check_noerr( err );
2412 }
2413 }
2414
2415 exit:
2416
2417 return ( err );
2418 }
2419
2420
2421 //===========================================================================================================================
2422 // GetRouteDestination
2423 //===========================================================================================================================
2424
2425 static OSStatus
2426 GetRouteDestination(DWORD * ifIndex, DWORD * address)
2427 {
2428 struct in_addr ia;
2429 IP_ADAPTER_INFO * pAdapterInfo = NULL;
2430 IP_ADAPTER_INFO * pAdapter = NULL;
2431 ULONG bufLen;
2432 mDNSBool done = mDNSfalse;
2433 OSStatus err;
2434
2435 //
2436 // GetBestInterface will fail if there is no default gateway
2437 // configured. If that happens, we will just take the first
2438 // interface in the list. MSDN support says there is no surefire
2439 // way to manually determine what the best interface might
2440 // be for a particular network address.
2441 //
2442 ia.s_addr = inet_addr(kLLNetworkAddr);
2443 err = GetBestInterface(*(IPAddr*) &ia, ifIndex);
2444
2445 if (err)
2446 {
2447 *ifIndex = 0;
2448 }
2449
2450 //
2451 // Make an initial call to GetAdaptersInfo to get
2452 // the necessary size into the bufLen variable
2453 //
2454 err = GetAdaptersInfo( NULL, &bufLen);
2455 require_action( err == ERROR_BUFFER_OVERFLOW, exit, err = kUnknownErr );
2456
2457 pAdapterInfo = (IP_ADAPTER_INFO*) malloc( bufLen );
2458 require_action( pAdapterInfo, exit, err = kNoMemoryErr );
2459
2460 err = GetAdaptersInfo( pAdapterInfo, &bufLen);
2461 require_noerr( err, exit );
2462
2463 pAdapter = pAdapterInfo;
2464 err = kUnknownErr;
2465
2466 // <rdar://problem/3718122>
2467 // <rdar://problem/5652098>
2468 //
2469 // Look for the Nortel VPN virtual interface, along with Juniper virtual interface.
2470 //
2471 // If these interfaces are active (i.e., has a non-zero IP Address),
2472 // then we want to disable routing table modifications.
2473
2474 while (pAdapter)
2475 {
2476 if ( ( IsNortelVPN( pAdapter ) || IsJuniperVPN( pAdapter ) || IsCiscoVPN( pAdapter ) ) &&
2477 ( inet_addr( pAdapter->IpAddressList.IpAddress.String ) != 0 ) )
2478 {
2479 dlog( kDebugLevelTrace, DEBUG_NAME "disabling routing table management due to VPN incompatibility" );
2480 goto exit;
2481 }
2482
2483 pAdapter = pAdapter->Next;
2484 }
2485
2486 while ( !done )
2487 {
2488 pAdapter = pAdapterInfo;
2489 err = kUnknownErr;
2490
2491 while (pAdapter)
2492 {
2493 // If we don't have an interface selected, choose the first one that is of type ethernet and
2494 // has a valid IP Address
2495
2496 if ((pAdapter->Type == MIB_IF_TYPE_ETHERNET) && ( IsValidAddress( pAdapter->IpAddressList.IpAddress.String ) ) && (!(*ifIndex) || (pAdapter->Index == (*ifIndex))))
2497 {
2498 *address = inet_addr( pAdapter->IpAddressList.IpAddress.String );
2499 *ifIndex = pAdapter->Index;
2500 err = kNoErr;
2501 break;
2502 }
2503
2504 pAdapter = pAdapter->Next;
2505 }
2506
2507 // If we found the right interface, or we weren't trying to find a specific interface then we're done
2508
2509 if ( !err || !( *ifIndex) )
2510 {
2511 done = mDNStrue;
2512 }
2513
2514 // Otherwise, try again by wildcarding the interface
2515
2516 else
2517 {
2518 *ifIndex = 0;
2519 }
2520 }
2521
2522 exit:
2523
2524 if ( pAdapterInfo != NULL )
2525 {
2526 free( pAdapterInfo );
2527 }
2528
2529 return( err );
2530 }
2531
2532
2533 static bool
2534 IsNortelVPN( IP_ADAPTER_INFO * pAdapter )
2535 {
2536 return ((pAdapter->Type == MIB_IF_TYPE_ETHERNET) &&
2537 (pAdapter->AddressLength == 6) &&
2538 (pAdapter->Address[0] == 0x44) &&
2539 (pAdapter->Address[1] == 0x45) &&
2540 (pAdapter->Address[2] == 0x53) &&
2541 (pAdapter->Address[3] == 0x54) &&
2542 (pAdapter->Address[4] == 0x42) &&
2543 (pAdapter->Address[5] == 0x00)) ? true : false;
2544 }
2545
2546
2547 static bool
2548 IsJuniperVPN( IP_ADAPTER_INFO * pAdapter )
2549 {
2550 return ( strnistr( pAdapter->Description, "Juniper", sizeof( pAdapter->Description ) ) != NULL ) ? true : false;
2551 }
2552
2553
2554 static bool
2555 IsCiscoVPN( IP_ADAPTER_INFO * pAdapter )
2556 {
2557 return ((pAdapter->Type == MIB_IF_TYPE_ETHERNET) &&
2558 (pAdapter->AddressLength == 6) &&
2559 (pAdapter->Address[0] == 0x00) &&
2560 (pAdapter->Address[1] == 0x05) &&
2561 (pAdapter->Address[2] == 0x9a) &&
2562 (pAdapter->Address[3] == 0x3c) &&
2563 (pAdapter->Address[4] == 0x7a) &&
2564 (pAdapter->Address[5] == 0x00)) ? true : false;
2565 }
2566
2567
2568 static const char *
2569 strnistr( const char * string, const char * subString, size_t max )
2570 {
2571 size_t subStringLen;
2572 size_t offset;
2573 size_t maxOffset;
2574 size_t stringLen;
2575 const char * pPos;
2576
2577 if ( ( string == NULL ) || ( subString == NULL ) )
2578 {
2579 return string;
2580 }
2581
2582 stringLen = ( max > strlen( string ) ) ? strlen( string ) : max;
2583
2584 if ( stringLen == 0 )
2585 {
2586 return NULL;
2587 }
2588
2589 subStringLen = strlen( subString );
2590
2591 if ( subStringLen == 0 )
2592 {
2593 return string;
2594 }
2595
2596 if ( subStringLen > stringLen )
2597 {
2598 return NULL;
2599 }
2600
2601 maxOffset = stringLen - subStringLen;
2602 pPos = string;
2603
2604 for ( offset = 0; offset <= maxOffset; offset++ )
2605 {
2606 if ( _strnicmp( pPos, subString, subStringLen ) == 0 )
2607 {
2608 return pPos;
2609 }
2610
2611 pPos++;
2612 }
2613
2614 return NULL;
2615 }
2616