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