]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSWindows/SystemService/Service.c
mDNSResponder-320.5.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
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 gPlatformStorage.reportStatusFunc = ReportStatus;
1193
1194 err = mDNS_Init( &gMDNSRecord, &gPlatformStorage, gRRCache, RR_CACHE_SIZE, mDNS_Init_AdvertiseLocalAddresses, CoreCallback, mDNS_Init_NoInitCallbackContext);
1195 require_noerr( err, exit);
1196
1197 err = SetupNotifications();
1198 check_noerr( err );
1199
1200 err = udsserver_init(mDNSNULL, 0);
1201 require_noerr( err, exit);
1202
1203 //
1204 // Get the version of Windows that we're running on
1205 //
1206 osInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
1207 ok = GetVersionEx( &osInfo );
1208 err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
1209 require_noerr( err, exit );
1210 gOSMajorVersion = osInfo.dwMajorVersion;
1211 gOSMinorVersion = osInfo.dwMinorVersion;
1212
1213 SetLLRoute( &gMDNSRecord );
1214
1215 exit:
1216 if( err != kNoErr )
1217 {
1218 ServiceSpecificFinalize( argc, argv );
1219 }
1220 return( err );
1221 }
1222
1223 //===========================================================================================================================
1224 // ServiceSpecificRun
1225 //===========================================================================================================================
1226
1227 static OSStatus ServiceSpecificRun( int argc, LPTSTR argv[] )
1228 {
1229 HANDLE * waitList;
1230 int waitListCount;
1231 DWORD timeout;
1232 DWORD result;
1233 BOOL done;
1234 mStatus err;
1235
1236 DEBUG_UNUSED( argc );
1237 DEBUG_UNUSED( argv );
1238
1239 timeout = ( gRetryFirewall ) ? kRetryFirewallPeriod : INFINITE;
1240
1241 err = SetupInterfaceList( &gMDNSRecord );
1242 check( !err );
1243
1244 err = uDNS_SetupDNSConfig( &gMDNSRecord );
1245 check( !err );
1246
1247 done = FALSE;
1248
1249 // Main event loop.
1250
1251 while( !done )
1252 {
1253 waitList = NULL;
1254 waitListCount = 0;
1255
1256 err = SetupWaitList( &gMDNSRecord, &waitList, &waitListCount );
1257 require_noerr( err, exit );
1258
1259 gEventSourceListChanged = FALSE;
1260
1261 while ( !gEventSourceListChanged )
1262 {
1263 static mDNSs32 RepeatedBusy = 0;
1264 mDNSs32 nextTimerEvent;
1265
1266 // Give the mDNS core a chance to do its work and determine next event time.
1267
1268 nextTimerEvent = udsserver_idle( mDNS_Execute( &gMDNSRecord ) - mDNS_TimeNow( &gMDNSRecord ) );
1269
1270 if ( nextTimerEvent < 0) nextTimerEvent = 0;
1271 else if ( nextTimerEvent > (0x7FFFFFFF / 1000)) nextTimerEvent = 0x7FFFFFFF / mDNSPlatformOneSecond;
1272 else nextTimerEvent = ( nextTimerEvent * 1000) / mDNSPlatformOneSecond;
1273
1274 // Debugging sanity check, to guard against CPU spins
1275
1276 if ( nextTimerEvent > 0 )
1277 {
1278 RepeatedBusy = 0;
1279 }
1280 else
1281 {
1282 nextTimerEvent = 1;
1283
1284 if ( ++RepeatedBusy >= mDNSPlatformOneSecond )
1285 {
1286 ShowTaskSchedulingError( &gMDNSRecord );
1287 RepeatedBusy = 0;
1288 }
1289 }
1290
1291 if ( gMDNSRecord.ShutdownTime )
1292 {
1293 mDNSs32 now = mDNS_TimeNow( &gMDNSRecord );
1294
1295 if ( mDNS_ExitNow( &gMDNSRecord, now ) )
1296 {
1297 mDNS_FinalExit( &gMDNSRecord );
1298 done = TRUE;
1299 break;
1300 }
1301
1302 if ( nextTimerEvent - gMDNSRecord.ShutdownTime >= 0 )
1303 {
1304 nextTimerEvent = gMDNSRecord.ShutdownTime;
1305 }
1306 }
1307
1308 // Wait until something occurs (e.g. cancel, incoming packet, or timeout).
1309 //
1310 // Note: There seems to be a bug in WinSock with respect to Alertable I/O. According
1311 // to MSDN <http://msdn.microsoft.com/en-us/library/aa363772(VS.85).aspx>, Alertable I/O
1312 // callbacks will only be invoked during the following calls (when the caller sets
1313 // the appropriate flag):
1314 //
1315 // - SleepEx
1316 // - WaitForSingleObjectEx
1317 // - WaitForMultipleObjectsEx
1318 // - SignalObjectAndWait
1319 // - MsgWaitForMultipleObjectsEx
1320 //
1321 // However, we have seen callbacks be invoked during calls to bind() (and maybe others). If there
1322 // weren't a bug, then socket events would only be queued during the call to WaitForMultipleObjects() and
1323 // we'd only have to check them once afterwards. However since that doesn't seem to be the case, we'll
1324 // check the queue both before we call WaitForMultipleObjects() and after.
1325
1326 DispatchSocketEvents( &gMDNSRecord );
1327 result = WaitForMultipleObjectsEx( ( DWORD ) waitListCount, waitList, FALSE, (DWORD) nextTimerEvent, TRUE );
1328 check( result != WAIT_FAILED );
1329 DispatchSocketEvents( &gMDNSRecord );
1330
1331 if ( result != WAIT_FAILED )
1332 {
1333 if ( result == WAIT_TIMEOUT )
1334 {
1335 // Next task timeout occurred. Loop back up to give mDNS core a chance to work.
1336
1337 dlog( kDebugLevelChatty - 1, DEBUG_NAME "timeout\n" );
1338 continue;
1339 }
1340 else if ( result == WAIT_IO_COMPLETION )
1341 {
1342 dlog( kDebugLevelChatty - 1, DEBUG_NAME "i/o completion\n" );
1343 continue;
1344 }
1345 else if ( result == kWaitListStopEvent )
1346 {
1347 // Stop event. Set the done flag and break to exit.
1348
1349 dlog( kDebugLevelVerbose, DEBUG_NAME "stopping...\n" );
1350 udsserver_exit();
1351 mDNS_StartExit( &gMDNSRecord );
1352 break;
1353 }
1354 else if( result == kWaitListInterfaceListChangedEvent )
1355 {
1356 int inBuffer;
1357 int outBuffer;
1358 DWORD outSize;
1359
1360 // It would be nice to come up with a more elegant solution to this, but it seems that
1361 // GetAdaptersAddresses doesn't always stay in sync after network changed events. So as
1362 // as a simple workaround, we'll pause for a couple of seconds before processing the change.
1363
1364 // We arrived at 2 secs by trial and error. We could reproduce the problem after sleeping
1365 // for 500 msec and 750 msec, but couldn't after sleeping for 1 sec. We added another
1366 // second on top of that to account for machine load or some other exigency.
1367
1368 Sleep( 2000 );
1369
1370 // Interface list changed event. Break out of the inner loop to re-setup the wait list.
1371
1372 InterfaceListDidChange( &gMDNSRecord );
1373
1374 // reset the event handler
1375 inBuffer = 0;
1376 outBuffer = 0;
1377 err = WSAIoctl( gInterfaceListChangedSocket, SIO_ADDRESS_LIST_CHANGE, &inBuffer, 0, &outBuffer, 0, &outSize, NULL, NULL );
1378 if( err < 0 )
1379 {
1380 check( errno_compat() == WSAEWOULDBLOCK );
1381 }
1382 }
1383 else if ( result == kWaitListComputerDescriptionEvent )
1384 {
1385 // The computer description might have changed
1386
1387 ComputerDescriptionDidChange( &gMDNSRecord );
1388 udsserver_handle_configchange( &gMDNSRecord );
1389
1390 // and reset the event handler
1391 if ( ( gDescKey != NULL ) && ( gDescChangedEvent != NULL ) )
1392 {
1393 err = RegNotifyChangeKeyValue( gDescKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET, gDescChangedEvent, TRUE);
1394 check_noerr( err );
1395 }
1396 }
1397 else if ( result == kWaitListTCPIPEvent )
1398 {
1399 // The TCP/IP might have changed
1400
1401 TCPIPConfigDidChange( &gMDNSRecord );
1402 udsserver_handle_configchange( &gMDNSRecord );
1403
1404 // and reset the event handler
1405
1406 if ( ( gTcpipKey != NULL ) && ( gTcpipChangedEvent ) )
1407 {
1408 err = RegNotifyChangeKeyValue( gTcpipKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gTcpipChangedEvent, TRUE );
1409 check_noerr( err );
1410 }
1411 }
1412 else if ( result == kWaitListDynDNSEvent )
1413 {
1414 // The DynDNS config might have changed
1415
1416 DynDNSConfigDidChange( &gMDNSRecord );
1417 udsserver_handle_configchange( &gMDNSRecord );
1418
1419 // and reset the event handler
1420
1421 if ((gDdnsKey != NULL) && (gDdnsChangedEvent))
1422 {
1423 err = RegNotifyChangeKeyValue(gDdnsKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gDdnsChangedEvent, TRUE);
1424 check_noerr( err );
1425 }
1426 }
1427 else if ( result == kWaitListFileShareEvent )
1428 {
1429 // File sharing changed
1430
1431 FileSharingDidChange( &gMDNSRecord );
1432
1433 // and reset the event handler
1434
1435 if ((gFileSharingKey != NULL) && (gFileSharingChangedEvent))
1436 {
1437 err = RegNotifyChangeKeyValue(gFileSharingKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gFileSharingChangedEvent, TRUE);
1438 check_noerr( err );
1439 }
1440 }
1441 else if ( result == kWaitListFirewallEvent )
1442 {
1443 // Firewall configuration changed
1444
1445 FirewallDidChange( &gMDNSRecord );
1446
1447 // and reset the event handler
1448
1449 if ((gFirewallKey != NULL) && (gFirewallChangedEvent))
1450 {
1451 err = RegNotifyChangeKeyValue(gFirewallKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gFirewallChangedEvent, TRUE);
1452 check_noerr( err );
1453 }
1454 }
1455 else if ( result == kWaitListAdvertisedServicesEvent )
1456 {
1457 // Ultimately we'll want to manage multiple services, but right now the only service
1458 // we'll be managing is SMB.
1459
1460 FileSharingDidChange( &gMDNSRecord );
1461
1462 // and reset the event handler
1463
1464 if ( ( gAdvertisedServicesKey != NULL ) && ( gAdvertisedServicesChangedEvent ) )
1465 {
1466 err = RegNotifyChangeKeyValue(gAdvertisedServicesKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gAdvertisedServicesChangedEvent, TRUE);
1467 check_noerr( err );
1468 }
1469 }
1470 else if ( result == kWaitListSPSWakeupEvent )
1471 {
1472 LARGE_INTEGER timeout;
1473
1474 ReportStatus( EVENTLOG_INFORMATION_TYPE, "Maintenance wake" );
1475
1476 timeout.QuadPart = kSPSMaintenanceWakePeriod;
1477 timeout.QuadPart *= kSecondsTo100NSUnits;
1478
1479 SetWaitableTimer( gSPSSleepEvent, &timeout, 0, NULL, NULL, TRUE );
1480 }
1481 else if ( result == kWaitListSPSSleepEvent )
1482 {
1483 ReportStatus( EVENTLOG_INFORMATION_TYPE, "Returning to sleep after maintenance wake" );
1484
1485 // Calling SetSuspendState() doesn't invoke our sleep handlers, so we'll
1486 // call HandlePowerSuspend() explicity. This will reset the
1487 // maintenance wake timers.
1488
1489 HandlePowerSuspend( NULL );
1490 SetSuspendState( FALSE, FALSE, FALSE );
1491 }
1492 else
1493 {
1494 int waitItemIndex;
1495
1496 waitItemIndex = (int)( ( (int) result ) - WAIT_OBJECT_0 );
1497 dlog( kDebugLevelChatty, DEBUG_NAME "waitable event on %d\n", waitItemIndex );
1498 check( ( waitItemIndex >= 0 ) && ( waitItemIndex < waitListCount ) );
1499
1500 if ( ( waitItemIndex >= 0 ) && ( waitItemIndex < waitListCount ) )
1501 {
1502 HANDLE signaledEvent;
1503 int n = 0;
1504
1505 signaledEvent = waitList[ waitItemIndex ];
1506
1507 // If gCurrentSource is not NULL, then this routine has been called
1508 // re-entrantly which should never happen.
1509
1510 check( !gCurrentSource );
1511
1512 for ( gCurrentSource = gEventSourceList; gCurrentSource; )
1513 {
1514 EventSource * current = gCurrentSource;
1515
1516 if ( gCurrentSource->event == signaledEvent )
1517 {
1518 gCurrentSource->handler( &gMDNSRecord, gCurrentSource->event, gCurrentSource->context );
1519 ++n;
1520 break;
1521 }
1522
1523 // If the current node was removed as a result of calling
1524 // the handler, then gCurrentSource was already incremented to
1525 // the next node. If it wasn't removed, then increment it
1526 // ourselves
1527
1528 if ( gCurrentSource == current )
1529 {
1530 gCurrentSource = gCurrentSource->next;
1531 }
1532 }
1533
1534 gCurrentSource = NULL;
1535
1536 check( n > 0 );
1537 }
1538 else
1539 {
1540 dlog( kDebugLevelWarning, DEBUG_NAME "%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__, result );
1541 }
1542 }
1543 }
1544 else
1545 {
1546 Sleep( 3 * 1000 );
1547
1548 err = SetupInterfaceList( &gMDNSRecord );
1549 check( !err );
1550
1551 err = uDNS_SetupDNSConfig( &gMDNSRecord );
1552 check( !err );
1553
1554 break;
1555 }
1556 }
1557
1558 if ( waitList )
1559 {
1560 free( waitList );
1561 waitList = NULL;
1562 waitListCount = 0;
1563 }
1564 }
1565
1566 exit:
1567
1568 return( 0 );
1569 }
1570
1571 //===========================================================================================================================
1572 // ServiceSpecificStop
1573 //===========================================================================================================================
1574
1575 static OSStatus ServiceSpecificStop( void )
1576 {
1577 OSStatus err;
1578 BOOL ok;
1579
1580 ok = SetEvent(gStopEvent);
1581 err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
1582 require_noerr( err, exit );
1583 exit:
1584 return( err );
1585 }
1586
1587 //===========================================================================================================================
1588 // ServiceSpecificFinalize
1589 //===========================================================================================================================
1590
1591 static void ServiceSpecificFinalize( int argc, LPTSTR argv[] )
1592 {
1593 DEBUG_UNUSED( argc );
1594 DEBUG_UNUSED( argv );
1595
1596 //
1597 // clean up any open sessions
1598 //
1599 while ( gEventSourceList )
1600 {
1601 UnregisterWaitableEvent( &gMDNSRecord, gEventSourceList->event );
1602 }
1603
1604 //
1605 // clean up the notifications
1606 //
1607 TearDownNotifications();
1608
1609 //
1610 // clean up loaded library
1611 //
1612
1613 if( gIPHelperLibraryInstance )
1614 {
1615 gGetIpInterfaceEntryFunctionPtr = NULL;
1616
1617 FreeLibrary( gIPHelperLibraryInstance );
1618 gIPHelperLibraryInstance = NULL;
1619 }
1620 }
1621
1622
1623 //===========================================================================================================================
1624 // SetupNotifications
1625 //===========================================================================================================================
1626
1627 mDNSlocal mStatus SetupNotifications()
1628 {
1629 mStatus err;
1630 SocketRef sock;
1631 unsigned long param;
1632 int inBuffer;
1633 int outBuffer;
1634 DWORD outSize;
1635
1636 gStopEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
1637 err = translate_errno( gStopEvent, errno_compat(), kNoResourcesErr );
1638 require_noerr( err, exit );
1639
1640 // Register to listen for address list changes.
1641
1642 gInterfaceListChangedEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
1643 err = translate_errno( gInterfaceListChangedEvent, (mStatus) GetLastError(), kUnknownErr );
1644 require_noerr( err, exit );
1645
1646 sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
1647 err = translate_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
1648 require_noerr( err, exit );
1649 gInterfaceListChangedSocket = sock;
1650
1651 // Make the socket non-blocking so the WSAIoctl returns immediately with WSAEWOULDBLOCK. It will set the event
1652 // when a change to the interface list is detected.
1653
1654 param = 1;
1655 err = ioctlsocket( sock, FIONBIO, &param );
1656 err = translate_errno( err == 0, errno_compat(), kUnknownErr );
1657 require_noerr( err, exit );
1658
1659 inBuffer = 0;
1660 outBuffer = 0;
1661 err = WSAIoctl( sock, SIO_ADDRESS_LIST_CHANGE, &inBuffer, 0, &outBuffer, 0, &outSize, NULL, NULL );
1662 if( err < 0 )
1663 {
1664 check( errno_compat() == WSAEWOULDBLOCK );
1665 }
1666
1667 err = WSAEventSelect( sock, gInterfaceListChangedEvent, FD_ADDRESS_LIST_CHANGE );
1668 err = translate_errno( err == 0, errno_compat(), kUnknownErr );
1669 require_noerr( err, exit );
1670
1671 gDescChangedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
1672 err = translate_errno( gDescChangedEvent, (mStatus) GetLastError(), kUnknownErr );
1673 require_noerr( err, exit );
1674
1675 err = RegOpenKeyEx( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\parameters"), 0, KEY_READ, &gDescKey);
1676 check_translated_errno( err == 0, errno_compat(), kNameErr );
1677
1678 if ( gDescKey != NULL )
1679 {
1680 err = RegNotifyChangeKeyValue( gDescKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET, gDescChangedEvent, TRUE);
1681 require_noerr( err, exit );
1682 }
1683
1684 // This will catch all changes to tcp/ip networking, including changes to the domain search list
1685
1686 gTcpipChangedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
1687 err = translate_errno( gTcpipChangedEvent, (mStatus) GetLastError(), kUnknownErr );
1688 require_noerr( err, exit );
1689
1690 err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), &gTcpipKey );
1691 require_noerr( err, exit );
1692
1693 err = RegNotifyChangeKeyValue( gTcpipKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gTcpipChangedEvent, TRUE);
1694 require_noerr( err, exit );
1695
1696 // This will catch all changes to ddns configuration
1697
1698 gDdnsChangedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
1699 err = translate_errno( gDdnsChangedEvent, (mStatus) GetLastError(), kUnknownErr );
1700 require_noerr( err, exit );
1701
1702 err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode TEXT("\\DynDNS\\Setup"), &gDdnsKey );
1703 require_noerr( err, exit );
1704
1705 err = RegNotifyChangeKeyValue( gDdnsKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gDdnsChangedEvent, TRUE);
1706 require_noerr( err, exit );
1707
1708 // This will catch all changes to file sharing
1709
1710 gFileSharingChangedEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
1711 err = translate_errno( gFileSharingChangedEvent, (mStatus) GetLastError(), kUnknownErr );
1712 require_noerr( err, exit );
1713
1714 err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\Shares"), &gFileSharingKey );
1715
1716 // Just to make sure that initialization doesn't fail on some old OS
1717 // that doesn't have this key, we'll only add the notification if
1718 // the key exists.
1719
1720 if ( !err )
1721 {
1722 err = RegNotifyChangeKeyValue( gFileSharingKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gFileSharingChangedEvent, TRUE);
1723 require_noerr( err, exit );
1724 }
1725 else
1726 {
1727 err = mStatus_NoError;
1728 }
1729
1730 // This will catch changes to the Windows firewall
1731
1732 gFirewallChangedEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
1733 err = translate_errno( gFirewallChangedEvent, (mStatus) GetLastError(), kUnknownErr );
1734 require_noerr( err, exit );
1735
1736 // Just to make sure that initialization doesn't fail on some old OS
1737 // that doesn't have this key, we'll only add the notification if
1738 // the key exists.
1739
1740 err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\SharedAccess\\Parameters\\FirewallPolicy\\FirewallRules"), &gFirewallKey );
1741
1742 if ( !err )
1743 {
1744 err = RegNotifyChangeKeyValue( gFirewallKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gFirewallChangedEvent, TRUE);
1745 require_noerr( err, exit );
1746 }
1747 else
1748 {
1749 err = mStatus_NoError;
1750 }
1751
1752 // This will catch all changes to advertised services configuration
1753
1754 gAdvertisedServicesChangedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
1755 err = translate_errno( gAdvertisedServicesChangedEvent, (mStatus) GetLastError(), kUnknownErr );
1756 require_noerr( err, exit );
1757
1758 err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode TEXT("\\Services"), &gAdvertisedServicesKey );
1759 require_noerr( err, exit );
1760
1761 err = RegNotifyChangeKeyValue( gAdvertisedServicesKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gAdvertisedServicesChangedEvent, TRUE);
1762 require_noerr( err, exit );
1763
1764 gSPSWakeupEvent = CreateWaitableTimer( NULL, FALSE, NULL );
1765 err = translate_errno( gSPSWakeupEvent, (mStatus) GetLastError(), kUnknownErr );
1766 require_noerr( err, exit );
1767
1768 gSPSSleepEvent = CreateWaitableTimer( NULL, FALSE, NULL );
1769 err = translate_errno( gSPSSleepEvent, (mStatus) GetLastError(), kUnknownErr );
1770 require_noerr( err, exit );
1771
1772 gUDSEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
1773 err = translate_errno( gUDSEvent, ( mStatus ) GetLastError(), kUnknownErr );
1774 require_noerr( err, exit );
1775
1776 exit:
1777 if( err )
1778 {
1779 TearDownNotifications();
1780 }
1781 return( err );
1782 }
1783
1784 //===========================================================================================================================
1785 // TearDownNotifications
1786 //===========================================================================================================================
1787
1788 mDNSlocal mStatus TearDownNotifications()
1789 {
1790 if ( gStopEvent )
1791 {
1792 CloseHandle( gStopEvent );
1793 gStopEvent = NULL;
1794 }
1795
1796 if( IsValidSocket( gInterfaceListChangedSocket ) )
1797 {
1798 close_compat( gInterfaceListChangedSocket );
1799 gInterfaceListChangedSocket = kInvalidSocketRef;
1800 }
1801
1802 if( gInterfaceListChangedEvent )
1803 {
1804 CloseHandle( gInterfaceListChangedEvent );
1805 gInterfaceListChangedEvent = 0;
1806 }
1807
1808 if ( gDescChangedEvent != NULL )
1809 {
1810 CloseHandle( gDescChangedEvent );
1811 gDescChangedEvent = NULL;
1812 }
1813
1814 if ( gDescKey != NULL )
1815 {
1816 RegCloseKey( gDescKey );
1817 gDescKey = NULL;
1818 }
1819
1820 if ( gTcpipChangedEvent != NULL )
1821 {
1822 CloseHandle( gTcpipChangedEvent );
1823 gTcpipChangedEvent = NULL;
1824 }
1825
1826 if ( gDdnsChangedEvent != NULL )
1827 {
1828 CloseHandle( gDdnsChangedEvent );
1829 gDdnsChangedEvent = NULL;
1830 }
1831
1832 if ( gDdnsKey != NULL )
1833 {
1834 RegCloseKey( gDdnsKey );
1835 gDdnsKey = NULL;
1836 }
1837
1838 if ( gFileSharingChangedEvent != NULL )
1839 {
1840 CloseHandle( gFileSharingChangedEvent );
1841 gFileSharingChangedEvent = NULL;
1842 }
1843
1844 if ( gFileSharingKey != NULL )
1845 {
1846 RegCloseKey( gFileSharingKey );
1847 gFileSharingKey = NULL;
1848 }
1849
1850 if ( gFirewallChangedEvent != NULL )
1851 {
1852 CloseHandle( gFirewallChangedEvent );
1853 gFirewallChangedEvent = NULL;
1854 }
1855
1856 if ( gFirewallKey != NULL )
1857 {
1858 RegCloseKey( gFirewallKey );
1859 gFirewallKey = NULL;
1860 }
1861
1862 if ( gAdvertisedServicesChangedEvent != NULL )
1863 {
1864 CloseHandle( gAdvertisedServicesChangedEvent );
1865 gAdvertisedServicesChangedEvent = NULL;
1866 }
1867
1868 if ( gAdvertisedServicesKey != NULL )
1869 {
1870 RegCloseKey( gAdvertisedServicesKey );
1871 gAdvertisedServicesKey = NULL;
1872 }
1873
1874 if ( gSPSWakeupEvent )
1875 {
1876 CloseHandle( gSPSWakeupEvent );
1877 gSPSWakeupEvent = NULL;
1878 }
1879
1880 if ( gSPSSleepEvent )
1881 {
1882 CloseHandle( gSPSSleepEvent );
1883 gSPSSleepEvent = NULL;
1884 }
1885
1886 return( mStatus_NoError );
1887 }
1888
1889
1890 //===========================================================================================================================
1891 // RegisterWaitableEvent
1892 //===========================================================================================================================
1893
1894 static mStatus RegisterWaitableEvent( mDNS * const inMDNS, HANDLE event, void * context, RegisterWaitableEventHandler handler )
1895 {
1896 EventSource * source;
1897 mStatus err = mStatus_NoError;
1898
1899 ( void ) inMDNS;
1900 check( event );
1901 check( handler );
1902
1903 source = ( EventSource* ) malloc( sizeof( EventSource ) );
1904 require_action( source, exit, err = mStatus_NoMemoryErr );
1905 mDNSPlatformMemZero( source, sizeof( EventSource ) );
1906 source->event = event;
1907 source->context = context;
1908 source->handler = handler;
1909
1910 source->next = gEventSourceList;
1911 gEventSourceList = source;
1912 gEventSourceListChanged = TRUE;
1913 gEventSources++;
1914
1915 exit:
1916
1917 return err;
1918 }
1919
1920
1921 //===========================================================================================================================
1922 // UnregisterWaitableEvent
1923 //===========================================================================================================================
1924
1925 static void UnregisterWaitableEvent( mDNS * const inMDNS, HANDLE event )
1926 {
1927 EventSource * current = gEventSourceList;
1928 EventSource * last = NULL;
1929
1930 ( void ) inMDNS;
1931 check( event );
1932
1933 while ( current )
1934 {
1935 if ( current->event == event )
1936 {
1937 if ( last == NULL )
1938 {
1939 gEventSourceList = current->next;
1940 }
1941 else
1942 {
1943 last->next = current->next;
1944 }
1945
1946 gEventSourceListChanged = TRUE;
1947
1948 // Protect against removing the node that we happen
1949 // to be looking at as we iterate through the event
1950 // source list in ServiceSpecificRun()
1951
1952 if ( current == gCurrentSource )
1953 {
1954 gCurrentSource = current->next;
1955 }
1956
1957 gEventSources--;
1958 free( current );
1959
1960 break;
1961 }
1962
1963 last = current;
1964 current = current->next;
1965 }
1966 }
1967
1968
1969 //===========================================================================================================================
1970 // SetupWaitList
1971 //===========================================================================================================================
1972
1973 mDNSlocal mStatus SetupWaitList( mDNS * const inMDNS, HANDLE **outWaitList, int *outWaitListCount )
1974 {
1975 int waitListCount;
1976 HANDLE * waitList;
1977 HANDLE * waitItemPtr;
1978 EventSource * source;
1979 mStatus err;
1980
1981 dlog( kDebugLevelTrace, DEBUG_NAME "setting up wait list\n" );
1982
1983 ( void ) inMDNS;
1984 check( inMDNS->p );
1985 check( outWaitList );
1986 check( outWaitListCount );
1987
1988 // Allocate an array to hold all the objects to wait on.
1989
1990 waitListCount = kWaitListFixedItemCount + gEventSources;
1991 waitList = ( HANDLE* ) malloc( waitListCount * sizeof( *waitList ) );
1992 require_action( waitList, exit, err = mStatus_NoMemoryErr );
1993 waitItemPtr = waitList;
1994
1995 // Add the fixed wait items to the beginning of the list.
1996
1997 *waitItemPtr++ = gStopEvent;
1998 *waitItemPtr++ = gInterfaceListChangedEvent;
1999 *waitItemPtr++ = gDescChangedEvent;
2000 *waitItemPtr++ = gTcpipChangedEvent;
2001 *waitItemPtr++ = gDdnsChangedEvent;
2002 *waitItemPtr++ = gFileSharingChangedEvent;
2003 *waitItemPtr++ = gFirewallChangedEvent;
2004 *waitItemPtr++ = gAdvertisedServicesChangedEvent;
2005 *waitItemPtr++ = gSPSWakeupEvent;
2006 *waitItemPtr++ = gSPSSleepEvent;
2007
2008 for ( source = gEventSourceList; source; source = source->next )
2009 {
2010 *waitItemPtr++ = source->event;
2011 }
2012
2013 check( ( int )( waitItemPtr - waitList ) == waitListCount );
2014
2015 *outWaitList = waitList;
2016 *outWaitListCount = waitListCount;
2017 waitList = NULL;
2018 err = mStatus_NoError;
2019
2020 exit:
2021
2022 if( waitList )
2023 {
2024 free( waitList );
2025 }
2026
2027 dlog( kDebugLevelTrace, DEBUG_NAME "setting up wait list done (err=%d %m)\n", err, err );
2028 return( err );
2029 }
2030
2031
2032 //===========================================================================================================================
2033 // CoreCallback
2034 //===========================================================================================================================
2035
2036 static void
2037 CoreCallback(mDNS * const inMDNS, mStatus status)
2038 {
2039 if (status == mStatus_ConfigChanged)
2040 {
2041 SetLLRoute( inMDNS );
2042 }
2043 }
2044
2045
2046 //===========================================================================================================================
2047 // UDSCanAccept
2048 //===========================================================================================================================
2049
2050 mDNSlocal void UDSCanAccept( mDNS * const inMDNS, HANDLE event, void * context )
2051 {
2052 ( void ) inMDNS;
2053 ( void ) event;
2054
2055 if ( gUDSCallback )
2056 {
2057 gUDSCallback( ( int ) gUDSSocket, 0, context );
2058 }
2059 }
2060
2061
2062 //===========================================================================================================================
2063 // UDSCanRead
2064 //===========================================================================================================================
2065
2066 mDNSlocal void UDSCanRead( TCPSocket * sock )
2067 {
2068 udsEventCallback callback = ( udsEventCallback ) sock->userCallback;
2069
2070 if ( callback )
2071 {
2072 callback( (int) sock->fd, 0, sock->userContext );
2073 }
2074 }
2075
2076
2077 //===========================================================================================================================
2078 // udsSupportAddFDToEventLoop
2079 //===========================================================================================================================
2080
2081
2082 mStatus
2083 udsSupportAddFDToEventLoop( SocketRef fd, udsEventCallback callback, void *context, void **platform_data)
2084 {
2085 mStatus err = mStatus_NoError;
2086
2087 // We are using some knowledge of what is being passed to us here. If the fd is a listen socket,
2088 // then the "callback" parameter is NULL. If it is an actual read/write socket, then the "callback"
2089 // parameter is not null. This is important because we use waitable events for the listen socket
2090 // and alertable I/O for the read/write sockets.
2091
2092 if ( context )
2093 {
2094 TCPSocket * sock;
2095
2096 sock = malloc( sizeof( TCPSocket ) );
2097 require_action( sock, exit, err = mStatus_NoMemoryErr );
2098 mDNSPlatformMemZero( sock, sizeof( TCPSocket ) );
2099
2100 sock->fd = (SOCKET) fd;
2101 sock->readEventHandler = UDSCanRead;
2102 sock->userCallback = callback;
2103 sock->userContext = context;
2104 sock->m = &gMDNSRecord;
2105
2106 err = TCPAddSocket( sock->m, sock );
2107 require_noerr( err, exit );
2108
2109 *platform_data = sock;
2110 }
2111 else
2112 {
2113 gUDSSocket = fd;
2114 gUDSCallback = callback;
2115 gUDSEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
2116 err = translate_errno( gUDSEvent, (mStatus) GetLastError(), kUnknownErr );
2117 require_noerr( err, exit );
2118 err = WSAEventSelect( fd, gUDSEvent, FD_ACCEPT | FD_CLOSE );
2119 err = translate_errno( err == 0, WSAGetLastError(), kNoResourcesErr );
2120 require_noerr( err, exit );
2121 err = RegisterWaitableEvent( &gMDNSRecord, gUDSEvent, context, UDSCanAccept );
2122 require_noerr( err, exit );
2123 }
2124
2125 exit:
2126
2127 return err;
2128 }
2129
2130
2131 int
2132 udsSupportReadFD( SocketRef fd, char *buf, int len, int flags, void *platform_data )
2133 {
2134 TCPSocket * sock;
2135 mDNSBool closed;
2136 int ret;
2137
2138 ( void ) flags;
2139
2140 sock = ( TCPSocket* ) platform_data;
2141 require_action( sock, exit, ret = -1 );
2142 require_action( sock->fd == fd, exit, ret = -1 );
2143
2144 ret = mDNSPlatformReadTCP( sock, buf, len, &closed );
2145
2146 if ( closed )
2147 {
2148 ret = 0;
2149 }
2150
2151 exit:
2152
2153 return ret;
2154 }
2155
2156
2157 mStatus
2158 udsSupportRemoveFDFromEventLoop( SocketRef fd, void *platform_data) // Note: This also CLOSES the socket
2159 {
2160 mStatus err = kNoErr;
2161
2162 if ( platform_data != NULL )
2163 {
2164 TCPSocket * sock;
2165
2166 dlog( kDebugLevelInfo, DEBUG_NAME "session closed\n" );
2167 sock = ( TCPSocket* ) platform_data;
2168 check( sock->fd == fd );
2169 mDNSPlatformTCPCloseConnection( sock );
2170 }
2171 else if ( gUDSEvent != NULL )
2172 {
2173 UnregisterWaitableEvent( &gMDNSRecord, gUDSEvent );
2174 WSAEventSelect( fd, gUDSEvent, 0 );
2175 CloseHandle( gUDSEvent );
2176 gUDSEvent = NULL;
2177 }
2178
2179 return err;
2180 }
2181
2182
2183 mDNSexport void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay)
2184 {
2185 (void)m;
2186 (void)delay;
2187 // No-op, for now
2188 }
2189
2190
2191 //===========================================================================================================================
2192 // SystemWakeForNetworkAccess
2193 //===========================================================================================================================
2194
2195 mDNSu8
2196 SystemWakeForNetworkAccess( LARGE_INTEGER * timeout )
2197 {
2198 HKEY key = NULL;
2199 DWORD dwSize;
2200 DWORD enabled;
2201 mDNSu8 ok;
2202 SYSTEM_POWER_STATUS powerStatus;
2203 time_t startTime;
2204 time_t nextWakeupTime;
2205 int delta;
2206 DWORD err;
2207
2208 dlog( kDebugLevelInfo, DEBUG_NAME "SystemWakeForNetworkAccess\n" );
2209
2210 // Make sure we have a timer
2211
2212 require_action( gSPSWakeupEvent != NULL, exit, ok = FALSE );
2213 require_action( gSPSSleepEvent != NULL, exit, ok = FALSE );
2214
2215 // Make sure the user enabled bonjour sleep proxy client
2216
2217 err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Power Management", &key );
2218 require_action( !err, exit, ok = FALSE );
2219 dwSize = sizeof( DWORD );
2220 err = RegQueryValueEx( key, L"Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize );
2221 require_action( !err, exit, ok = FALSE );
2222 require_action( enabled, exit, ok = FALSE );
2223
2224 // Make sure machine is on AC power
2225
2226 ok = ( mDNSu8 ) GetSystemPowerStatus( &powerStatus );
2227 require_action( ok, exit, ok = FALSE );
2228 require_action( powerStatus.ACLineStatus == AC_LINE_ONLINE, exit, ok = FALSE );
2229
2230 // Now make sure we have a network interface that does wake-on-lan
2231
2232 ok = ( mDNSu8 ) IsWOMPEnabled( &gMDNSRecord );
2233 require_action( ok, exit, ok = FALSE );
2234
2235 // Now make sure we have advertised services. Doesn't make sense to
2236 // enable sleep proxy if we have no multicast services that could
2237 // potentially wake us up.
2238
2239 ok = ( mDNSu8 ) mDNSCoreHaveAdvertisedMulticastServices( &gMDNSRecord );
2240 require_action( ok, exit, ok = FALSE );
2241
2242 // Calculate next wake up time
2243
2244 startTime = time( NULL ); // Seconds since midnight January 1, 1970
2245 nextWakeupTime = startTime + ( 120 * 60 ); // 2 hours later
2246
2247 if ( gMDNSRecord.p->nextDHCPLeaseExpires < nextWakeupTime )
2248 {
2249 nextWakeupTime = gMDNSRecord.p->nextDHCPLeaseExpires;
2250 }
2251
2252 // Finally calculate the next relative wakeup time
2253
2254 delta = ( int )( ( ( double )( nextWakeupTime - startTime ) ) * 0.9 );
2255 ReportStatus( EVENTLOG_INFORMATION_TYPE, "enabling sleep proxy client with next maintenance wake in %d seconds", delta );
2256
2257 // Convert seconds to 100 nanosecond units expected by SetWaitableTimer
2258
2259 timeout->QuadPart = -delta;
2260 timeout->QuadPart *= kSecondsTo100NSUnits;
2261
2262 ok = TRUE;
2263
2264 exit:
2265
2266 if ( key )
2267 {
2268 RegCloseKey( key );
2269 }
2270
2271 return ok;
2272 }
2273
2274
2275 //===========================================================================================================================
2276 // HaveRoute
2277 //===========================================================================================================================
2278
2279 static bool
2280 HaveRoute( PMIB_IPFORWARDROW rowExtant, unsigned long addr, unsigned long metric )
2281 {
2282 PMIB_IPFORWARDTABLE pIpForwardTable = NULL;
2283 DWORD dwSize = 0;
2284 BOOL bOrder = FALSE;
2285 OSStatus err;
2286 bool found = false;
2287 unsigned long int i;
2288
2289 //
2290 // Find out how big our buffer needs to be.
2291 //
2292 err = GetIpForwardTable(NULL, &dwSize, bOrder);
2293 require_action( err == ERROR_INSUFFICIENT_BUFFER, exit, err = kUnknownErr );
2294
2295 //
2296 // Allocate the memory for the table
2297 //
2298 pIpForwardTable = (PMIB_IPFORWARDTABLE) malloc( dwSize );
2299 require_action( pIpForwardTable, exit, err = kNoMemoryErr );
2300
2301 //
2302 // Now get the table.
2303 //
2304 err = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder);
2305 require_noerr( err, exit );
2306
2307 //
2308 // Search for the row in the table we want.
2309 //
2310 for ( i = 0; i < pIpForwardTable->dwNumEntries; i++)
2311 {
2312 if ( ( pIpForwardTable->table[i].dwForwardDest == addr ) && ( !metric || ( pIpForwardTable->table[i].dwForwardMetric1 == metric ) ) )
2313 {
2314 memcpy( rowExtant, &(pIpForwardTable->table[i]), sizeof(*rowExtant) );
2315 found = true;
2316 break;
2317 }
2318 }
2319
2320 exit:
2321
2322 if ( pIpForwardTable != NULL )
2323 {
2324 free(pIpForwardTable);
2325 }
2326
2327 return found;
2328 }
2329
2330
2331 //===========================================================================================================================
2332 // IsValidAddress
2333 //===========================================================================================================================
2334
2335 static bool
2336 IsValidAddress( const char * addr )
2337 {
2338 return ( addr && ( strcmp( addr, "0.0.0.0" ) != 0 ) ) ? true : false;
2339 }
2340
2341
2342 //===========================================================================================================================
2343 // GetAdditionalMetric
2344 //===========================================================================================================================
2345
2346 static ULONG
2347 GetAdditionalMetric( DWORD ifIndex )
2348 {
2349 ULONG metric = 0;
2350
2351 if( !gIPHelperLibraryInstance )
2352 {
2353 gIPHelperLibraryInstance = LoadLibrary( TEXT( "Iphlpapi" ) );
2354
2355 gGetIpInterfaceEntryFunctionPtr =
2356 (GetIpInterfaceEntryFunctionPtr) GetProcAddress( gIPHelperLibraryInstance, "GetIpInterfaceEntry" );
2357
2358 if( !gGetIpInterfaceEntryFunctionPtr )
2359 {
2360 BOOL ok;
2361
2362 ok = FreeLibrary( gIPHelperLibraryInstance );
2363 check_translated_errno( ok, GetLastError(), kUnknownErr );
2364 gIPHelperLibraryInstance = NULL;
2365 }
2366 }
2367
2368 if ( gGetIpInterfaceEntryFunctionPtr )
2369 {
2370 MIB_IPINTERFACE_ROW row;
2371 DWORD err;
2372
2373 ZeroMemory( &row, sizeof( MIB_IPINTERFACE_ROW ) );
2374 row.Family = AF_INET;
2375 row.InterfaceIndex = ifIndex;
2376 err = gGetIpInterfaceEntryFunctionPtr( &row );
2377 require_noerr( err, exit );
2378 metric = row.Metric + 256;
2379 }
2380
2381 exit:
2382
2383 return metric;
2384 }
2385
2386
2387 //===========================================================================================================================
2388 // SetLLRoute
2389 //===========================================================================================================================
2390
2391 static OSStatus
2392 SetLLRoute( mDNS * const inMDNS )
2393 {
2394 OSStatus err = kNoErr;
2395
2396 DEBUG_UNUSED( inMDNS );
2397
2398 //
2399 // <rdar://problem/4096464> Don't call SetLLRoute on loopback
2400 // <rdar://problem/6885843> Default route on Windows 7 breaks network connectivity
2401 //
2402 // Don't mess w/ the routing table on Vista and later OSes, as
2403 // they have a permanent route to link-local addresses. Otherwise,
2404 // set a route to link local addresses (169.254.0.0)
2405 //
2406 if ( ( gOSMajorVersion < 6 ) && gServiceManageLLRouting && !gPlatformStorage.registeredLoopback4 )
2407 {
2408 DWORD ifIndex;
2409 MIB_IPFORWARDROW rowExtant;
2410 bool addRoute;
2411 MIB_IPFORWARDROW row;
2412
2413 ZeroMemory(&row, sizeof(row));
2414
2415 err = GetRouteDestination(&ifIndex, &row.dwForwardNextHop);
2416 require_noerr( err, exit );
2417 row.dwForwardDest = inet_addr(kLLNetworkAddr);
2418 row.dwForwardIfIndex = ifIndex;
2419 row.dwForwardMask = inet_addr(kLLNetworkAddrMask);
2420 row.dwForwardType = 3;
2421 row.dwForwardProto = MIB_IPPROTO_NETMGMT;
2422 row.dwForwardAge = 0;
2423 row.dwForwardPolicy = 0;
2424 row.dwForwardMetric1 = 20 + GetAdditionalMetric( ifIndex );
2425 row.dwForwardMetric2 = (DWORD) - 1;
2426 row.dwForwardMetric3 = (DWORD) - 1;
2427 row.dwForwardMetric4 = (DWORD) - 1;
2428 row.dwForwardMetric5 = (DWORD) - 1;
2429
2430 addRoute = true;
2431
2432 //
2433 // check to make sure we don't already have a route
2434 //
2435 if ( HaveRoute( &rowExtant, inet_addr( kLLNetworkAddr ), 0 ) )
2436 {
2437 //
2438 // set the age to 0 so that we can do a memcmp.
2439 //
2440 rowExtant.dwForwardAge = 0;
2441
2442 //
2443 // check to see if this route is the same as our route
2444 //
2445 if (memcmp(&row, &rowExtant, sizeof(row)) != 0)
2446 {
2447 //
2448 // if it isn't then delete this entry
2449 //
2450 DeleteIpForwardEntry(&rowExtant);
2451 }
2452 else
2453 {
2454 //
2455 // else it is, so we don't want to create another route
2456 //
2457 addRoute = false;
2458 }
2459 }
2460
2461 if (addRoute && row.dwForwardNextHop)
2462 {
2463 err = CreateIpForwardEntry(&row);
2464 check_noerr( err );
2465 }
2466 }
2467
2468 exit:
2469
2470 return ( err );
2471 }
2472
2473
2474 //===========================================================================================================================
2475 // GetRouteDestination
2476 //===========================================================================================================================
2477
2478 static OSStatus
2479 GetRouteDestination(DWORD * ifIndex, DWORD * address)
2480 {
2481 struct in_addr ia;
2482 IP_ADAPTER_INFO * pAdapterInfo = NULL;
2483 IP_ADAPTER_INFO * pAdapter = NULL;
2484 ULONG bufLen;
2485 mDNSBool done = mDNSfalse;
2486 OSStatus err;
2487
2488 //
2489 // GetBestInterface will fail if there is no default gateway
2490 // configured. If that happens, we will just take the first
2491 // interface in the list. MSDN support says there is no surefire
2492 // way to manually determine what the best interface might
2493 // be for a particular network address.
2494 //
2495 ia.s_addr = inet_addr(kLLNetworkAddr);
2496 err = GetBestInterface(*(IPAddr*) &ia, ifIndex);
2497
2498 if (err)
2499 {
2500 *ifIndex = 0;
2501 }
2502
2503 //
2504 // Make an initial call to GetAdaptersInfo to get
2505 // the necessary size into the bufLen variable
2506 //
2507 err = GetAdaptersInfo( NULL, &bufLen);
2508 require_action( err == ERROR_BUFFER_OVERFLOW, exit, err = kUnknownErr );
2509
2510 pAdapterInfo = (IP_ADAPTER_INFO*) malloc( bufLen );
2511 require_action( pAdapterInfo, exit, err = kNoMemoryErr );
2512
2513 err = GetAdaptersInfo( pAdapterInfo, &bufLen);
2514 require_noerr( err, exit );
2515
2516 pAdapter = pAdapterInfo;
2517 err = kUnknownErr;
2518
2519 // <rdar://problem/3718122>
2520 // <rdar://problem/5652098>
2521 //
2522 // Look for the Nortel VPN virtual interface, along with Juniper virtual interface.
2523 //
2524 // If these interfaces are active (i.e., has a non-zero IP Address),
2525 // then we want to disable routing table modifications.
2526
2527 while (pAdapter)
2528 {
2529 if ( ( IsNortelVPN( pAdapter ) || IsJuniperVPN( pAdapter ) || IsCiscoVPN( pAdapter ) ) &&
2530 ( inet_addr( pAdapter->IpAddressList.IpAddress.String ) != 0 ) )
2531 {
2532 dlog( kDebugLevelTrace, DEBUG_NAME "disabling routing table management due to VPN incompatibility" );
2533 goto exit;
2534 }
2535
2536 pAdapter = pAdapter->Next;
2537 }
2538
2539 while ( !done )
2540 {
2541 pAdapter = pAdapterInfo;
2542 err = kUnknownErr;
2543
2544 while (pAdapter)
2545 {
2546 // If we don't have an interface selected, choose the first one that is of type ethernet and
2547 // has a valid IP Address
2548
2549 if ((pAdapter->Type == MIB_IF_TYPE_ETHERNET) && ( IsValidAddress( pAdapter->IpAddressList.IpAddress.String ) ) && (!(*ifIndex) || (pAdapter->Index == (*ifIndex))))
2550 {
2551 *address = inet_addr( pAdapter->IpAddressList.IpAddress.String );
2552 *ifIndex = pAdapter->Index;
2553 err = kNoErr;
2554 break;
2555 }
2556
2557 pAdapter = pAdapter->Next;
2558 }
2559
2560 // If we found the right interface, or we weren't trying to find a specific interface then we're done
2561
2562 if ( !err || !( *ifIndex) )
2563 {
2564 done = mDNStrue;
2565 }
2566
2567 // Otherwise, try again by wildcarding the interface
2568
2569 else
2570 {
2571 *ifIndex = 0;
2572 }
2573 }
2574
2575 exit:
2576
2577 if ( pAdapterInfo != NULL )
2578 {
2579 free( pAdapterInfo );
2580 }
2581
2582 return( err );
2583 }
2584
2585
2586 static bool
2587 IsNortelVPN( IP_ADAPTER_INFO * pAdapter )
2588 {
2589 return ((pAdapter->Type == MIB_IF_TYPE_ETHERNET) &&
2590 (pAdapter->AddressLength == 6) &&
2591 (pAdapter->Address[0] == 0x44) &&
2592 (pAdapter->Address[1] == 0x45) &&
2593 (pAdapter->Address[2] == 0x53) &&
2594 (pAdapter->Address[3] == 0x54) &&
2595 (pAdapter->Address[4] == 0x42) &&
2596 (pAdapter->Address[5] == 0x00)) ? true : false;
2597 }
2598
2599
2600 static bool
2601 IsJuniperVPN( IP_ADAPTER_INFO * pAdapter )
2602 {
2603 return ( strnistr( pAdapter->Description, "Juniper", sizeof( pAdapter->Description ) ) != NULL ) ? true : false;
2604 }
2605
2606
2607 static bool
2608 IsCiscoVPN( IP_ADAPTER_INFO * pAdapter )
2609 {
2610 return ((pAdapter->Type == MIB_IF_TYPE_ETHERNET) &&
2611 (pAdapter->AddressLength == 6) &&
2612 (pAdapter->Address[0] == 0x00) &&
2613 (pAdapter->Address[1] == 0x05) &&
2614 (pAdapter->Address[2] == 0x9a) &&
2615 (pAdapter->Address[3] == 0x3c) &&
2616 (pAdapter->Address[4] == 0x7a) &&
2617 (pAdapter->Address[5] == 0x00)) ? true : false;
2618 }
2619
2620
2621 static const char *
2622 strnistr( const char * string, const char * subString, size_t max )
2623 {
2624 size_t subStringLen;
2625 size_t offset;
2626 size_t maxOffset;
2627 size_t stringLen;
2628 const char * pPos;
2629
2630 if ( ( string == NULL ) || ( subString == NULL ) )
2631 {
2632 return string;
2633 }
2634
2635 stringLen = ( max > strlen( string ) ) ? strlen( string ) : max;
2636
2637 if ( stringLen == 0 )
2638 {
2639 return NULL;
2640 }
2641
2642 subStringLen = strlen( subString );
2643
2644 if ( subStringLen == 0 )
2645 {
2646 return string;
2647 }
2648
2649 if ( subStringLen > stringLen )
2650 {
2651 return NULL;
2652 }
2653
2654 maxOffset = stringLen - subStringLen;
2655 pPos = string;
2656
2657 for ( offset = 0; offset <= maxOffset; offset++ )
2658 {
2659 if ( _strnicmp( pPos, subString, subStringLen ) == 0 )
2660 {
2661 return pPos;
2662 }
2663
2664 pPos++;
2665 }
2666
2667 return NULL;
2668 }
2669