1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 Change History (most recent first):
20 Revision 1.49 2009/07/17 19:59:46 herscher
21 <rdar://problem/7062660> Update the womp settings for each network adapter immediately preceding the call to mDNSCoreMachineSleep().
23 Revision 1.48 2009/07/09 21:34:14 herscher
24 <rdar://problem/3775717> SDK: Port mDNSNetMonitor to Windows. Refactor the system service slightly by removing the main() function from Service.c so that mDNSNetMonitor can link to functions defined in Service.c
26 Revision 1.47 2009/07/07 21:35:06 herscher
27 <rdar://problem/6713286> windows platform changes to support use as sleep proxy client
29 Revision 1.46 2009/06/05 18:28:24 herscher
30 <rdar://problem/6125087> mDNSResponder should be able to identify VPN adapters generically
31 <rdar://problem/6885843> WIN7: Bonjour removes the default gateway entry and thereby breaks network connectivity
33 Revision 1.45 2009/04/30 20:07:51 mcguire
34 <rdar://problem/6822674> Support multiple UDSs from launchd
36 Revision 1.44 2009/03/30 20:41:36 herscher
37 <rdar://problem/5925472> Current Bonjour code does not compile on Windows
38 <rdar://problem/6330821> Bonjour for Windows incompatible w/Juniper Network Connect. Do a substring search for "Juniper" in the description field
39 of the network adapter.
40 <rdar://problem/6122028> Bonjour for Windows incompatible w/Cisco AnyConnect VPN Client
41 <rdar://problem/5652098> Bonjour for Windows incompatible w/Juniper Network Connect. Update the adapter name per info received from Juniper
42 <rdar://problem/5781566> Core: Default Gateway set to 0.0.0.0 on Vista causes ARP flood
43 <rdar://problem/5991983> Change the registry values from Apple Computer, Inc. to Apple Inc.
44 <rdar://problem/5301328> wchar/sizeof mismatch in CheckFirewall()
46 Revision 1.43 2009/01/13 05:31:35 mkrochma
47 <rdar://problem/6491367> Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy
49 Revision 1.42 2007/02/14 01:58:19 cheshire
50 <rdar://problem/4995831> Don't delete Unix Domain Socket on exit if we didn't create it on startup
52 Revision 1.41 2007/02/06 19:06:49 cheshire
53 <rdar://problem/3956518> Need to go native with launchd
55 Revision 1.40 2007/01/05 05:46:08 cheshire
56 Add mDNS *const m parameter to udsserver_handle_configchange()
58 Revision 1.39 2006/08/14 23:26:07 cheshire
59 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
61 Revision 1.38 2005/10/05 20:55:15 herscher
62 <rdar://problem/4096464> Don't call SetLLRoute on loopback interface
64 Revision 1.37 2005/10/05 18:05:28 herscher
65 <rdar://problem/4192011> Save Wide-Area preferences in a different spot in the registry so they don't get removed when doing an update install.
67 Revision 1.36 2005/09/11 22:12:42 herscher
68 <rdar://problem/4247793> Remove dependency on WMI. Ensure that the Windows firewall is turned on before trying to configure it.
70 Revision 1.35 2005/06/30 18:29:49 shersche
71 <rdar://problem/4090059> Don't overwrite the localized service description text
73 Revision 1.34 2005/04/22 07:34:23 shersche
74 Check an interface's address and make sure it's valid before using it to set link-local routes.
76 Revision 1.33 2005/04/13 17:48:23 shersche
77 <rdar://problem/4079667> Make sure there is only one default route for link-local addresses.
79 Revision 1.32 2005/04/06 01:32:05 shersche
80 Remove default route for link-local addressing when another interface comes up with a routable IPv4 address
82 Revision 1.31 2005/04/06 01:00:11 shersche
83 <rdar://problem/4080127> GetFullPathName() should be passed the number of TCHARs in the path buffer, not the size in bytes of the path buffer.
85 Revision 1.30 2005/04/06 00:52:43 shersche
86 <rdar://problem/4079667> Only add default route if there are no other routable IPv4 addresses on any of the other interfaces. More work needs to be done to correctly configure the routing table when multiple interfaces are extant and none of them have routable IPv4 addresses.
88 Revision 1.29 2005/03/06 05:21:56 shersche
89 <rdar://problem/4037635> Fix corrupt UTF-8 name when non-ASCII system name used, enabled unicode support
91 Revision 1.28 2005/03/03 02:27:24 shersche
92 Include the RegNames.h header file for names of registry keys
94 Revision 1.27 2005/03/02 20:12:59 shersche
97 Revision 1.26 2005/02/15 08:00:27 shersche
98 <rdar://problem/4007151> Update name
100 Revision 1.25 2005/02/10 22:35:36 cheshire
101 <rdar://problem/3727944> Update name
103 Revision 1.24 2005/01/27 20:02:43 cheshire
104 udsSupportRemoveFDFromEventLoop() needs to close the SocketRef as well
106 Revision 1.23 2005/01/25 08:14:15 shersche
107 Change CacheRecord to CacheEntity
109 Revision 1.22 2004/12/10 13:18:40 cheshire
110 Create no-op function RecordUpdatedNiceLabel(), required by uds_daemon.c
112 Revision 1.21 2004/11/10 04:03:41 shersche
113 Remove SharedAccess dependency. This causes problems on XP SP1, and isn't necessary for XP SP2 because we already are dependent on WMI, which itself is dependent on SharedAccess.
115 Revision 1.20 2004/10/14 21:44:05 shersche
116 <rdar://problem/3838237> Fix a race condition between the socket thread and the main processing thread that resulted in the socket thread accessing a previously deleted Win32EventSource object.
119 Revision 1.19 2004/10/12 17:59:55 shersche
120 <rdar://problem/3718122> Disable routing table modifications when Nortel VPN adapter is active
123 Revision 1.18 2004/10/11 21:57:50 shersche
124 <rdar://problem/3832450> The SharedAccess service dependency causes a circular dependency on Windows Server 2003. Only add the SharedAccess service dependency if running on XP. All other platforms do not manipulate the firewall and thus are not dependent on it.
127 Revision 1.17 2004/09/17 01:08:58 cheshire
128 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
129 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
130 declared in that file are ONLY appropriate to single-address-space embedded applications.
131 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
133 Revision 1.16 2004/09/16 18:49:34 shersche
134 Remove the XP SP2 check before attempting to manage the firewall. There is a race condition in the SP2 updater such that upon first reboot after the upgrade, mDNSResponder might not know that it is running under SP2 yet. This necessitates a second reboot before the firewall is managed. Removing the check will cause mDNSResponder to try and manage the firewall everytime it boots up, if and only if it hasn't managed the firewall a previous time.
136 Revision 1.15 2004/09/15 17:13:33 shersche
139 Revision 1.14 2004/09/15 09:37:25 shersche
140 Add SharedAccess to dependency list, call CheckFirewall after sending status back to SCM
142 Revision 1.13 2004/09/13 07:35:10 shersche
143 <rdar://problem/3762235> Add mDNSResponder to Windows Firewall application list if SP2 is detected and app hasn't been added before
146 Revision 1.12 2004/09/11 21:18:32 shersche
147 <rdar://problem/3779502> Add route to ARP everything when a 169.254.x.x address is selected
150 Revision 1.11 2004/09/11 05:39:19 shersche
151 <rdar://problem/3780203> Detect power managment state changes, calling mDNSCoreMachineSleep(m, true) on sleep, and mDNSCoreMachineSleep(m, false) on resume
154 Revision 1.10 2004/08/16 21:45:24 shersche
155 Use the full pathname of executable when calling CreateService()
156 Submitted by: prepin@zetron.com
158 Revision 1.9 2004/08/11 01:59:41 cheshire
159 Remove "mDNS *globalInstance" parameter from udsserver_init()
161 Revision 1.8 2004/08/05 05:40:05 shersche
162 <rdar://problem/3751566> Only invoke SetConsoleCtrlHandler when running directly from command line.
163 <rdar://problem/3751481> Invoke udsserver_handle_configchange() when the computer description changes
164 Bug #: 3751481, 3751566
166 Revision 1.7 2004/07/26 05:35:07 shersche
167 ignore non-enet interfaces when setting up link-local routing
169 Revision 1.6 2004/07/20 06:48:26 shersche
170 <rdar://problem/3718122> Allow registry entries to dictate whether to manage link local routing
173 Revision 1.5 2004/07/09 19:08:07 shersche
174 <rdar://problem/3713762> ServiceSetupEventLogging() errors are handled gracefully
177 Revision 1.4 2004/06/24 20:58:15 shersche
178 Fix compiler error in Release build
179 Submitted by: herscher
181 Revision 1.3 2004/06/24 15:28:53 shersche
182 Automatically setup routes to link-local addresses upon interface list change events.
183 Submitted by: herscher
185 Revision 1.2 2004/06/23 16:56:00 shersche
186 <rdar://problem/3697326> locked call to udsserver_idle().
188 Submitted by: herscher
190 Revision 1.1 2004/06/18 04:16:41 rpantos
193 Revision 1.1 2004/01/30 02:58:39 bradley
194 mDNSResponder Windows Service. Provides global Bonjour support with an IPC interface.
204 #include "CommonServices.h"
205 #include "DebugServices.h"
206 #include "RegNames.h"
208 #include "uds_daemon.h"
209 #include "GenLinkedList.h"
212 #include "Resource.h"
214 #include "mDNSEmbeddedAPI.h"
215 #include "mDNSWin32.h"
217 #include "Firewall.h"
219 #if( !TARGET_OS_WINDOWS_CE )
222 #include <ipExport.h>
224 #include <ws2ipdef.h>
225 #include <iphlpapi.h>
226 #include <netioapi.h>
228 #include <powrprof.h>
231 #ifndef HeapEnableTerminationOnCorruption
232 # define HeapEnableTerminationOnCorruption (HEAP_INFORMATION_CLASS)1
236 #pragma mark == Constants ==
239 //===========================================================================================================================
241 //===========================================================================================================================
243 #define DEBUG_NAME "[Server] "
244 #define kServiceFirewallName L"Bonjour"
245 #define kServiceDependencies TEXT("Tcpip\0\0")
246 #define kDNSServiceCacheEntryCountDefault 512
247 #define kRetryFirewallPeriod 30 * 1000
248 #define kDefValueSize MAX_PATH + 1
250 #define kDefaultRouteMetric 399
252 #define RR_CACHE_SIZE 500
253 static CacheEntity gRRCache
[RR_CACHE_SIZE
];
255 #pragma mark == Structures ==
258 //===========================================================================================================================
260 //===========================================================================================================================
261 //---------------------------------------------------------------------------------------------------------------------------
262 /*! @typedef EventSourceFlags
264 @abstract Session flags.
266 @constant EventSourceFlagsNone No flags.
267 @constant EventSourceFlagsThreadDone Thread is no longer active.
268 @constant EventSourceFlagsNoClose Do not close the session when the thread exits.
269 @constant EventSourceFinalized Finalize has been called for this session
272 typedef uint32_t EventSourceFlags
;
274 #define EventSourceFlagsNone 0
275 #define EventSourceFlagsThreadDone ( 1 << 2 )
276 #define EventSourceFlagsNoClose ( 1 << 3 )
277 #define EventSourceFinalized ( 1 << 4 )
280 typedef struct Win32EventSource
282 EventSourceFlags flags
;
287 udsEventCallback callback
;
292 struct Win32EventSource
* next
;
297 #pragma mark == Prototypes ==
300 //===========================================================================================================================
302 //===========================================================================================================================
303 static void Usage( void );
304 static BOOL WINAPI
ConsoleControlHandler( DWORD inControlEvent
);
305 static OSStatus
InstallService( LPCTSTR inName
, LPCTSTR inDisplayName
, LPCTSTR inDescription
, LPCTSTR inPath
);
306 static OSStatus
RemoveService( LPCTSTR inName
);
307 static OSStatus
SetServiceParameters();
308 static OSStatus
GetServiceParameters();
309 static OSStatus
CheckFirewall();
310 static OSStatus
SetServiceInfo( SC_HANDLE inSCM
, LPCTSTR inServiceName
, LPCTSTR inDescription
);
311 static void ReportStatus( int inType
, const char *inFormat
, ... );
313 static void WINAPI
ServiceMain( DWORD argc
, LPTSTR argv
[] );
314 static OSStatus
ServiceSetupEventLogging( void );
315 static DWORD WINAPI
ServiceControlHandler( DWORD inControl
, DWORD inEventType
, LPVOID inEventData
, LPVOID inContext
);
317 static OSStatus
ServiceRun( int argc
, LPTSTR argv
[] );
318 static void ServiceStop( void );
320 static OSStatus
ServiceSpecificInitialize( int argc
, LPTSTR argv
[] );
321 static OSStatus
ServiceSpecificRun( int argc
, LPTSTR argv
[] );
322 static OSStatus
ServiceSpecificStop( void );
323 static void ServiceSpecificFinalize( int argc
, LPTSTR argv
[] );
324 static mStatus
EventSourceFinalize(Win32EventSource
* source
);
325 static void EventSourceLock();
326 static void EventSourceUnlock();
327 static mDNSs32
udsIdle(mDNS
* const inMDNS
, mDNSs32 interval
);
328 static void CoreCallback(mDNS
* const inMDNS
, mStatus result
);
329 static void HostDescriptionChanged(mDNS
* const inMDNS
);
330 static mDNSu8
SystemWakeForNetworkAccess( LARGE_INTEGER
* timeout
);
331 static OSStatus
GetRouteDestination(DWORD
* ifIndex
, DWORD
* address
);
332 static OSStatus
SetLLRoute( mDNS
* const inMDNS
);
333 static bool HaveRoute( PMIB_IPFORWARDROW rowExtant
, unsigned long addr
, unsigned long metric
);
334 static bool IsValidAddress( const char * addr
);
335 static bool IsNortelVPN( IP_ADAPTER_INFO
* pAdapter
);
336 static bool IsJuniperVPN( IP_ADAPTER_INFO
* pAdapter
);
337 static bool IsCiscoVPN( IP_ADAPTER_INFO
* pAdapter
);
338 static const char * strnistr( const char * string
, const char * subString
, size_t max
);
341 # define StrLen(X) wcslen(X)
342 # define StrCmp(X,Y) wcscmp(X,Y)
344 # define StrLen(X) strlen(X)
345 # define StrCmp(X,Y) strcmp(X,Y)
349 #define kLLNetworkAddr "169.254.0.0"
350 #define kLLNetworkAddrMask "255.255.0.0"
353 #include "mDNSEmbeddedAPI.h"
356 #pragma mark == Globals ==
359 //===========================================================================================================================
361 //===========================================================================================================================
362 #define gMDNSRecord mDNSStorage
363 DEBUG_LOCAL mDNS_PlatformSupport gPlatformStorage
;
364 DEBUG_LOCAL BOOL gServiceQuietMode
= FALSE
;
365 DEBUG_LOCAL SERVICE_TABLE_ENTRY gServiceDispatchTable
[] =
367 { kServiceName
, ServiceMain
},
370 DEBUG_LOCAL SERVICE_STATUS gServiceStatus
;
371 DEBUG_LOCAL SERVICE_STATUS_HANDLE gServiceStatusHandle
= NULL
;
372 DEBUG_LOCAL HANDLE gServiceEventSource
= NULL
;
373 DEBUG_LOCAL
bool gServiceAllowRemote
= false;
374 DEBUG_LOCAL
int gServiceCacheEntryCount
= 0; // 0 means to use the DNS-SD default.
375 DEBUG_LOCAL
bool gServiceManageLLRouting
= true;
376 DEBUG_LOCAL
int gWaitCount
= 0;
377 DEBUG_LOCAL HANDLE
* gWaitList
= NULL
;
378 DEBUG_LOCAL HANDLE gStopEvent
= NULL
;
379 DEBUG_LOCAL HANDLE gSPSWakeupEvent
= NULL
;
380 DEBUG_LOCAL HANDLE gSPSSleepEvent
= NULL
;
381 DEBUG_LOCAL CRITICAL_SECTION gEventSourceLock
;
382 DEBUG_LOCAL GenLinkedList gEventSources
;
383 DEBUG_LOCAL BOOL gRetryFirewall
= FALSE
;
384 DEBUG_LOCAL DWORD gOSMajorVersion
;
385 DEBUG_LOCAL DWORD gOSMinorVersion
;
387 typedef DWORD ( WINAPI
* GetIpInterfaceEntryFunctionPtr
)( PMIB_IPINTERFACE_ROW
);
388 mDNSlocal HMODULE gIPHelperLibraryInstance
= NULL
;
389 mDNSlocal GetIpInterfaceEntryFunctionPtr gGetIpInterfaceEntryFunctionPtr
= NULL
;
396 //===========================================================================================================================
398 //===========================================================================================================================
399 int Main( int argc
, LPTSTR argv
[] )
406 HeapSetInformation( NULL
, HeapEnableTerminationOnCorruption
, NULL
, 0 );
408 debug_initialize( kDebugOutputTypeMetaConsole
);
409 debug_set_property( kDebugPropertyTagPrintLevel
, kDebugLevelVerbose
);
411 // Default to automatically starting the service dispatcher if no extra arguments are specified.
413 start
= ( argc
<= 1 );
417 for( i
= 1; i
< argc
; ++i
)
419 if( StrCmp( argv
[ i
], TEXT("-install") ) == 0 ) // Install
424 LoadString( GetModuleHandle( NULL
), IDS_SERVICE_DESCRIPTION
, desc
, sizeof( desc
) );
425 err
= InstallService( kServiceName
, kServiceName
, desc
, argv
[0] );
428 ReportStatus( EVENTLOG_ERROR_TYPE
, "install service failed (%d)\n", err
);
432 else if( StrCmp( argv
[ i
], TEXT("-remove") ) == 0 ) // Remove
434 err
= RemoveService( kServiceName
);
437 ReportStatus( EVENTLOG_ERROR_TYPE
, "remove service failed (%d)\n", err
);
441 else if( StrCmp( argv
[ i
], TEXT("-start") ) == 0 ) // Start
445 else if( StrCmp( argv
[ i
], TEXT("-server") ) == 0 ) // Server
447 err
= RunDirect( argc
, argv
);
450 ReportStatus( EVENTLOG_ERROR_TYPE
, "run service directly failed (%d)\n", err
);
454 else if( StrCmp( argv
[ i
], TEXT("-q") ) == 0 ) // Quiet Mode (toggle)
456 gServiceQuietMode
= !gServiceQuietMode
;
458 else if( ( StrCmp( argv
[ i
], TEXT("-help") ) == 0 ) || // Help
459 ( StrCmp( argv
[ i
], TEXT("-h") ) == 0 ) )
473 // Start the service dispatcher if requested. This does not return until all services have terminated. If any
474 // global initialization is needed, it should be done before starting the service dispatcher, but only if it
475 // will take less than 30 seconds. Otherwise, use a separate thread for it and start the dispatcher immediately.
479 ok
= StartServiceCtrlDispatcher( gServiceDispatchTable
);
480 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kInUseErr
);
483 ReportStatus( EVENTLOG_ERROR_TYPE
, "start service dispatcher failed (%d)\n", err
);
490 dlog( kDebugLevelTrace
, DEBUG_NAME
"exited (%d %m)\n", err
, err
);
494 //===========================================================================================================================
496 //===========================================================================================================================
498 static void Usage( void )
500 fprintf( stderr
, "\n" );
501 fprintf( stderr
, "mDNSResponder 1.0d1\n" );
502 fprintf( stderr
, "\n" );
503 fprintf( stderr
, " <no args> Runs the service normally\n" );
504 fprintf( stderr
, " -install Creates the service and starts it\n" );
505 fprintf( stderr
, " -remove Stops the service and deletes it\n" );
506 fprintf( stderr
, " -start Starts the service dispatcher after processing all other arguments\n" );
507 fprintf( stderr
, " -server Runs the service directly as a server (for debugging)\n" );
508 fprintf( stderr
, " -q Toggles Quiet Mode (no events or output)\n" );
509 fprintf( stderr
, " -remote Allow remote connections\n" );
510 fprintf( stderr
, " -cache n Number of mDNS cache entries (defaults to %d)\n", kDNSServiceCacheEntryCountDefault
);
511 fprintf( stderr
, " -h[elp] Display Help/Usage\n" );
512 fprintf( stderr
, "\n" );
515 //===========================================================================================================================
516 // ConsoleControlHandler
517 //===========================================================================================================================
519 static BOOL WINAPI
ConsoleControlHandler( DWORD inControlEvent
)
525 switch( inControlEvent
)
528 case CTRL_BREAK_EVENT
:
529 case CTRL_CLOSE_EVENT
:
530 case CTRL_LOGOFF_EVENT
:
531 case CTRL_SHUTDOWN_EVENT
:
532 err
= ServiceSpecificStop();
533 require_noerr( err
, exit
);
546 //===========================================================================================================================
548 //===========================================================================================================================
550 static OSStatus
InstallService( LPCTSTR inName
, LPCTSTR inDisplayName
, LPCTSTR inDescription
, LPCTSTR inPath
)
556 TCHAR fullPath
[ MAX_PATH
];
563 // Get a full path to the executable since a relative path may have been specified.
565 size
= GetFullPathName( inPath
, MAX_PATH
, fullPath
, &namePtr
);
566 err
= translate_errno( size
> 0, (OSStatus
) GetLastError(), kPathErr
);
567 require_noerr( err
, exit
);
569 // Create the service and start it.
571 scm
= OpenSCManager( NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
572 err
= translate_errno( scm
, (OSStatus
) GetLastError(), kOpenErr
);
573 require_noerr( err
, exit
);
575 service
= CreateService( scm
, inName
, inDisplayName
, SERVICE_ALL_ACCESS
, SERVICE_WIN32_SHARE_PROCESS
,
576 SERVICE_AUTO_START
, SERVICE_ERROR_NORMAL
, fullPath
, NULL
, NULL
, kServiceDependencies
,
578 err
= translate_errno( service
, (OSStatus
) GetLastError(), kDuplicateErr
);
579 require_noerr( err
, exit
);
581 err
= SetServiceParameters();
586 err
= SetServiceInfo( scm
, inName
, inDescription
);
590 ok
= StartService( service
, 0, NULL
);
591 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kInUseErr
);
592 require_noerr( err
, exit
);
594 ReportStatus( EVENTLOG_SUCCESS
, "installed service \"%s\"/\"%s\" at \"%s\"\n", inName
, inDisplayName
, inPath
);
600 CloseServiceHandle( service
);
604 CloseServiceHandle( scm
);
609 //===========================================================================================================================
611 //===========================================================================================================================
613 static OSStatus
RemoveService( LPCTSTR inName
)
619 SERVICE_STATUS status
;
624 // Open a connection to the service.
626 scm
= OpenSCManager( 0, 0, SC_MANAGER_ALL_ACCESS
);
627 err
= translate_errno( scm
, (OSStatus
) GetLastError(), kOpenErr
);
628 require_noerr( err
, exit
);
630 service
= OpenService( scm
, inName
, SERVICE_STOP
| SERVICE_QUERY_STATUS
| DELETE
);
631 err
= translate_errno( service
, (OSStatus
) GetLastError(), kNotFoundErr
);
632 require_noerr( err
, exit
);
634 // Stop the service, if it is not already stopped, then delete it.
636 ok
= QueryServiceStatus( service
, &status
);
637 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kAuthenticationErr
);
638 require_noerr( err
, exit
);
640 if( status
.dwCurrentState
!= SERVICE_STOPPED
)
642 ok
= ControlService( service
, SERVICE_CONTROL_STOP
, &status
);
643 check_translated_errno( ok
, (OSStatus
) GetLastError(), kAuthenticationErr
);
646 ok
= DeleteService( service
);
647 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kDeletedErr
);
648 require_noerr( err
, exit
);
650 ReportStatus( EVENTLOG_SUCCESS
, "Removed service \"%s\"\n", inName
);
656 CloseServiceHandle( service
);
660 CloseServiceHandle( scm
);
667 //===========================================================================================================================
668 // SetServiceParameters
669 //===========================================================================================================================
671 static OSStatus
SetServiceParameters()
674 DWORD valueLen
= sizeof(DWORD
);
682 // Add/Open Parameters section under service entry in registry
684 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
, &key
);
685 require_noerr( err
, exit
);
688 // If the value isn't already there, then we create it
690 err
= RegQueryValueEx(key
, kServiceManageLLRouting
, 0, &type
, (LPBYTE
) &value
, &valueLen
);
692 if (err
!= ERROR_SUCCESS
)
696 err
= RegSetValueEx( key
, kServiceManageLLRouting
, 0, REG_DWORD
, (const LPBYTE
) &value
, sizeof(DWORD
) );
697 require_noerr( err
, exit
);
712 //===========================================================================================================================
713 // GetServiceParameters
714 //===========================================================================================================================
716 static OSStatus
GetServiceParameters()
727 // Add/Open Parameters section under service entry in registry
729 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
, &key
);
730 require_noerr( err
, exit
);
732 valueLen
= sizeof(DWORD
);
733 err
= RegQueryValueEx(key
, kServiceManageLLRouting
, 0, &type
, (LPBYTE
) &value
, &valueLen
);
734 if (err
== ERROR_SUCCESS
)
736 gServiceManageLLRouting
= (value
) ? true : false;
739 valueLen
= sizeof(DWORD
);
740 err
= RegQueryValueEx(key
, kServiceCacheEntryCount
, 0, &type
, (LPBYTE
) &value
, &valueLen
);
741 if (err
== ERROR_SUCCESS
)
743 gServiceCacheEntryCount
= value
;
757 //===========================================================================================================================
759 //===========================================================================================================================
761 static OSStatus
CheckFirewall()
766 ENUM_SERVICE_STATUS
* lpService
= NULL
;
770 DWORD bytesNeeded
= 0;
772 DWORD resumeHandle
= 0;
777 BOOL isRunning
= FALSE
;
778 OSStatus err
= kUnknownErr
;
780 // Check to see if the firewall service is running. If it isn't, then
781 // we want to return immediately
783 sc
= OpenSCManager( NULL
, NULL
, SC_MANAGER_ENUMERATE_SERVICE
);
784 err
= translate_errno( sc
, GetLastError(), kUnknownErr
);
785 require_noerr( err
, exit
);
787 srvType
= SERVICE_WIN32
;
788 srvState
= SERVICE_STATE_ALL
;
792 // Call EnumServicesStatus using the handle returned by OpenSCManager
794 ok
= EnumServicesStatus ( sc
, srvType
, srvState
, lpService
, dwBytes
, &bytesNeeded
, &srvCount
, &resumeHandle
);
796 if ( ok
|| ( GetLastError() != ERROR_MORE_DATA
) )
806 dwBytes
= bytesNeeded
;
808 lpService
= ( ENUM_SERVICE_STATUS
* ) malloc( dwBytes
);
809 require_action( lpService
, exit
, err
= mStatus_NoMemoryErr
);
812 err
= translate_errno( ok
, GetLastError(), kUnknownErr
);
813 require_noerr( err
, exit
);
815 for ( i
= 0; i
< srvCount
; i
++ )
817 if ( wcscmp( lpService
[i
].lpServiceName
, L
"SharedAccess" ) == 0 )
819 if ( lpService
[i
].ServiceStatus
.dwCurrentState
== SERVICE_RUNNING
)
828 require_action( isRunning
, exit
, err
= kUnknownErr
);
830 // Check to see if we've managed the firewall.
831 // This package might have been installed, then
832 // the OS was upgraded to SP2 or above. If that's
833 // the case, then we need to manipulate the firewall
834 // so networking works correctly.
836 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
, &key
);
837 require_noerr( err
, exit
);
839 valueLen
= sizeof(DWORD
);
840 err
= RegQueryValueEx(key
, kServiceManageFirewall
, 0, &type
, (LPBYTE
) &value
, &valueLen
);
842 if ((err
!= ERROR_SUCCESS
) || (value
== 0))
844 wchar_t fullPath
[ MAX_PATH
];
847 // Get a full path to the executable
849 size
= GetModuleFileNameW( NULL
, fullPath
, MAX_PATH
);
850 err
= translate_errno( size
> 0, (OSStatus
) GetLastError(), kPathErr
);
851 require_noerr( err
, exit
);
853 err
= mDNSAddToFirewall(fullPath
, kServiceFirewallName
);
854 require_noerr( err
, exit
);
857 err
= RegSetValueEx( key
, kServiceManageFirewall
, 0, REG_DWORD
, (const LPBYTE
) &value
, sizeof( DWORD
) );
858 require_noerr( err
, exit
);
875 CloseServiceHandle ( sc
);
883 //===========================================================================================================================
885 //===========================================================================================================================
887 static OSStatus
SetServiceInfo( SC_HANDLE inSCM
, LPCTSTR inServiceName
, LPCTSTR inDescription
)
892 SERVICE_DESCRIPTION description
;
893 SERVICE_FAILURE_ACTIONS actions
;
897 check( inServiceName
);
898 check( inDescription
);
903 // Open the database (if not provided) and lock it to prevent other access while re-configuring.
907 inSCM
= OpenSCManager( NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
908 err
= translate_errno( inSCM
, (OSStatus
) GetLastError(), kOpenErr
);
909 require_noerr( err
, exit
);
912 lock
= LockServiceDatabase( inSCM
);
913 err
= translate_errno( lock
, (OSStatus
) GetLastError(), kInUseErr
);
914 require_noerr( err
, exit
);
916 // Open a handle to the service.
918 service
= OpenService( inSCM
, inServiceName
, SERVICE_CHANGE_CONFIG
|SERVICE_START
);
919 err
= translate_errno( service
, (OSStatus
) GetLastError(), kNotFoundErr
);
920 require_noerr( err
, exit
);
922 // Change the description.
924 description
.lpDescription
= (LPTSTR
) inDescription
;
925 ok
= ChangeServiceConfig2( service
, SERVICE_CONFIG_DESCRIPTION
, &description
);
926 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kParamErr
);
927 require_noerr( err
, exit
);
929 actions
.dwResetPeriod
= INFINITE
;
930 actions
.lpRebootMsg
= NULL
;
931 actions
.lpCommand
= NULL
;
932 actions
.cActions
= 1;
933 actions
.lpsaActions
= &action
;
935 action
.Type
= SC_ACTION_RESTART
;
937 ok
= ChangeServiceConfig2( service
, SERVICE_CONFIG_FAILURE_ACTIONS
, &actions
);
938 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kParamErr
);
939 require_noerr( err
, exit
);
944 // Close the service and release the lock.
948 CloseServiceHandle( service
);
952 UnlockServiceDatabase( lock
);
957 //===========================================================================================================================
959 //===========================================================================================================================
961 static void ReportStatus( int inType
, const char *inFormat
, ... )
963 if( !gServiceQuietMode
)
967 va_start( args
, inFormat
);
968 if( gServiceEventSource
)
972 const char * array
[ 1 ];
974 vsprintf( s
, inFormat
, args
);
976 ok
= ReportEventA( gServiceEventSource
, (WORD
) inType
, 0, 0x20000001L
, NULL
, 1, 0, array
, NULL
);
977 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
983 n
= vfprintf( stderr
, inFormat
, args
);
990 //===========================================================================================================================
992 //===========================================================================================================================
994 int RunDirect( int argc
, LPTSTR argv
[] )
1000 initialized
= FALSE
;
1002 // Install a Console Control Handler to handle things like control-c signals.
1004 ok
= SetConsoleCtrlHandler( ConsoleControlHandler
, TRUE
);
1005 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
1006 require_noerr( err
, exit
);
1008 err
= ServiceSpecificInitialize( argc
, argv
);
1009 require_noerr( err
, exit
);
1012 // Run the service. This does not return until the service quits or is stopped.
1014 ReportStatus( EVENTLOG_SUCCESS
, "Running \"%s\" service directly\n", kServiceName
);
1016 err
= ServiceSpecificRun( argc
, argv
);
1017 require_noerr( err
, exit
);
1024 ServiceSpecificFinalize( argc
, argv
);
1033 //===========================================================================================================================
1035 //===========================================================================================================================
1037 static void WINAPI
ServiceMain( DWORD argc
, LPTSTR argv
[] )
1042 err
= ServiceSetupEventLogging();
1045 err
= GetServiceParameters();
1048 // Initialize the service status and register the service control handler with the name of the service.
1050 gServiceStatus
.dwServiceType
= SERVICE_WIN32_SHARE_PROCESS
;
1051 gServiceStatus
.dwCurrentState
= 0;
1052 gServiceStatus
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
|SERVICE_ACCEPT_POWEREVENT
;
1053 gServiceStatus
.dwWin32ExitCode
= NO_ERROR
;
1054 gServiceStatus
.dwServiceSpecificExitCode
= NO_ERROR
;
1055 gServiceStatus
.dwCheckPoint
= 0;
1056 gServiceStatus
.dwWaitHint
= 0;
1058 gServiceStatusHandle
= RegisterServiceCtrlHandlerEx( argv
[ 0 ], ServiceControlHandler
, NULL
);
1059 err
= translate_errno( gServiceStatusHandle
, (OSStatus
) GetLastError(), kInUseErr
);
1060 require_noerr( err
, exit
);
1062 // Mark the service as starting.
1064 gServiceStatus
.dwCurrentState
= SERVICE_START_PENDING
;
1065 gServiceStatus
.dwCheckPoint
= 0;
1066 gServiceStatus
.dwWaitHint
= 5000; // 5 seconds
1067 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
1068 check_translated_errno( ok
, GetLastError(), kParamErr
);
1070 // Run the service. This does not return until the service quits or is stopped.
1072 err
= ServiceRun( (int) argc
, argv
);
1075 gServiceStatus
.dwWin32ExitCode
= ERROR_SERVICE_SPECIFIC_ERROR
;
1076 gServiceStatus
.dwServiceSpecificExitCode
= (DWORD
) err
;
1079 // Service-specific work is done so mark the service as stopped.
1081 gServiceStatus
.dwCurrentState
= SERVICE_STOPPED
;
1082 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
1083 check_translated_errno( ok
, GetLastError(), kParamErr
);
1085 // Note: The service status handle should not be closed according to Microsoft documentation.
1088 if( gServiceEventSource
)
1090 ok
= DeregisterEventSource( gServiceEventSource
);
1091 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
1092 gServiceEventSource
= NULL
;
1096 //===========================================================================================================================
1097 // ServiceSetupEventLogging
1098 //===========================================================================================================================
1100 static OSStatus
ServiceSetupEventLogging( void )
1105 DWORD typesSupported
;
1106 TCHAR path
[ MAX_PATH
];
1111 // Add/Open source name as a sub-key under the Application key in the EventLog registry key.
1113 s
= TEXT("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\") kServiceName
;
1114 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, s
, &key
);
1115 require_noerr( err
, exit
);
1117 // Add the name to the EventMessageFile subkey.
1120 GetModuleFileName( NULL
, path
, MAX_PATH
);
1121 n
= (DWORD
) ( ( StrLen( path
) + 1 ) * sizeof( TCHAR
) );
1122 err
= RegSetValueEx( key
, TEXT("EventMessageFile"), 0, REG_EXPAND_SZ
, (const LPBYTE
) path
, n
);
1123 require_noerr( err
, exit
);
1125 // Set the supported event types in the TypesSupported subkey.
1129 | EVENTLOG_ERROR_TYPE
1130 | EVENTLOG_WARNING_TYPE
1131 | EVENTLOG_INFORMATION_TYPE
1132 | EVENTLOG_AUDIT_SUCCESS
1133 | EVENTLOG_AUDIT_FAILURE
;
1134 err
= RegSetValueEx( key
, TEXT("TypesSupported"), 0, REG_DWORD
, (const LPBYTE
) &typesSupported
, sizeof( DWORD
) );
1135 require_noerr( err
, exit
);
1137 // Set up the event source.
1139 gServiceEventSource
= RegisterEventSource( NULL
, kServiceName
);
1140 err
= translate_errno( gServiceEventSource
, (OSStatus
) GetLastError(), kParamErr
);
1141 require_noerr( err
, exit
);
1151 //===========================================================================================================================
1152 // ServiceControlHandler
1153 //===========================================================================================================================
1155 static DWORD WINAPI
ServiceControlHandler( DWORD inControl
, DWORD inEventType
, LPVOID inEventData
, LPVOID inContext
)
1160 DEBUG_UNUSED( inEventData
);
1161 DEBUG_UNUSED( inContext
);
1166 case SERVICE_CONTROL_STOP
:
1167 dlog( kDebugLevelInfo
, DEBUG_NAME
"ServiceControlHandler: SERVICE_CONTROL_STOP\n" );
1173 case SERVICE_CONTROL_POWEREVENT
:
1175 if (inEventType
== PBT_APMSUSPEND
)
1177 LARGE_INTEGER timeout
;
1179 dlog( kDebugLevelInfo
, DEBUG_NAME
"ServiceControlHandler: PBT_APMSUSPEND\n" );
1181 mDNSPlatformLock( &gMDNSRecord
);
1183 gMDNSRecord
.SystemWakeOnLANEnabled
= SystemWakeForNetworkAccess( &timeout
);
1185 if ( gMDNSRecord
.SystemWakeOnLANEnabled
)
1187 ok
= SetWaitableTimer( gSPSWakeupEvent
, &timeout
, 0, NULL
, NULL
, TRUE
);
1191 mDNSPlatformUnlock( &gMDNSRecord
);
1193 mDNSCoreMachineSleep(&gMDNSRecord
, TRUE
);
1195 else if (inEventType
== PBT_APMRESUMESUSPEND
)
1197 dlog( kDebugLevelInfo
, DEBUG_NAME
"ServiceControlHandler: PBT_APMRESUMESUSPEND\n" );
1199 mDNSPlatformLock( &gMDNSRecord
);
1201 if ( gSPSWakeupEvent
)
1203 CancelWaitableTimer( gSPSWakeupEvent
);
1206 if ( gSPSSleepEvent
)
1208 CancelWaitableTimer( gSPSSleepEvent
);
1211 mDNSPlatformUnlock( &gMDNSRecord
);
1213 mDNSCoreMachineSleep(&gMDNSRecord
, FALSE
);
1219 dlog( kDebugLevelNotice
, DEBUG_NAME
"ServiceControlHandler: event (0x%08X)\n", inControl
);
1223 if( setStatus
&& gServiceStatusHandle
)
1225 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
1226 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
1232 //===========================================================================================================================
1234 //===========================================================================================================================
1236 static OSStatus
ServiceRun( int argc
, LPTSTR argv
[] )
1242 DEBUG_UNUSED( argc
);
1243 DEBUG_UNUSED( argv
);
1245 initialized
= FALSE
;
1247 // <rdar://problem/5727548> Make the service as running before we call ServiceSpecificInitialize. We've
1248 // had reports that some machines with McAfee firewall installed cause a problem with iTunes installation.
1249 // We think that the firewall product is interferring with code in ServiceSpecificInitialize. So as a
1250 // simple workaround, we'll mark us as running *before* we call ServiceSpecificInitialize. This will unblock
1251 // any installers that are waiting for our state to change.
1253 gServiceStatus
.dwCurrentState
= SERVICE_RUNNING
;
1254 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
1255 check_translated_errno( ok
, GetLastError(), kParamErr
);
1257 // Initialize the service-specific stuff
1259 err
= ServiceSpecificInitialize( argc
, argv
);
1260 require_noerr( err
, exit
);
1263 err
= CheckFirewall();
1268 gRetryFirewall
= TRUE
;
1271 // Run the service-specific stuff. This does not return until the service quits or is stopped.
1273 ReportStatus( EVENTLOG_INFORMATION_TYPE
, "mDNSResponder started\n" );
1274 err
= ServiceSpecificRun( argc
, argv
);
1275 ReportStatus( EVENTLOG_INFORMATION_TYPE
, "mDNSResponder stopped (%d)\n", err
);
1276 require_noerr( err
, exit
);
1278 // Service stopped. Clean up and we're done.
1283 ServiceSpecificFinalize( argc
, argv
);
1288 //===========================================================================================================================
1290 //===========================================================================================================================
1292 static void ServiceStop( void )
1297 // Signal the event to cause the service to exit.
1299 if( gServiceStatusHandle
)
1301 gServiceStatus
.dwCurrentState
= SERVICE_STOP_PENDING
;
1302 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
1303 check_translated_errno( ok
, GetLastError(), kParamErr
);
1306 err
= ServiceSpecificStop();
1312 #pragma mark == Service Specific ==
1315 //===========================================================================================================================
1316 // ServiceSpecificInitialize
1317 //===========================================================================================================================
1319 static OSStatus
ServiceSpecificInitialize( int argc
, LPTSTR argv
[] )
1321 OSVERSIONINFO osInfo
;
1325 DEBUG_UNUSED( argc
);
1326 DEBUG_UNUSED( argv
);
1328 mDNSPlatformMemZero( &gMDNSRecord
, sizeof gMDNSRecord
);
1329 mDNSPlatformMemZero( &gPlatformStorage
, sizeof gPlatformStorage
);
1331 gPlatformStorage
.idleThreadCallback
= udsIdle
;
1332 gPlatformStorage
.hostDescriptionChangedCallback
= HostDescriptionChanged
;
1334 InitializeCriticalSection(&gEventSourceLock
);
1336 gStopEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1337 err
= translate_errno( gStopEvent
, errno_compat(), kNoResourcesErr
);
1338 require_noerr( err
, exit
);
1340 gSPSWakeupEvent
= CreateWaitableTimer( NULL
, FALSE
, NULL
);
1341 err
= translate_errno( gSPSWakeupEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1342 require_noerr( err
, exit
);
1344 gSPSSleepEvent
= CreateWaitableTimer( NULL
, FALSE
, NULL
);
1345 err
= translate_errno( gSPSSleepEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1346 require_noerr( err
, exit
);
1348 err
= mDNS_Init( &gMDNSRecord
, &gPlatformStorage
, gRRCache
, RR_CACHE_SIZE
, mDNS_Init_AdvertiseLocalAddresses
, CoreCallback
, mDNS_Init_NoInitCallbackContext
);
1349 require_noerr( err
, exit
);
1351 err
= udsserver_init(mDNSNULL
, 0);
1352 require_noerr( err
, exit
);
1355 // Get the version of Windows that we're running on
1357 osInfo
.dwOSVersionInfoSize
= sizeof( OSVERSIONINFO
);
1358 ok
= GetVersionEx( &osInfo
);
1359 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
1360 require_noerr( err
, exit
);
1361 gOSMajorVersion
= osInfo
.dwMajorVersion
;
1362 gOSMinorVersion
= osInfo
.dwMinorVersion
;
1364 SetLLRoute( &gMDNSRecord
);
1369 ServiceSpecificFinalize( argc
, argv
);
1374 //===========================================================================================================================
1375 // ServiceSpecificRun
1376 //===========================================================================================================================
1378 static OSStatus
ServiceSpecificRun( int argc
, LPTSTR argv
[] )
1383 DEBUG_UNUSED( argc
);
1384 DEBUG_UNUSED( argv
);
1386 // Main event loop. Process connection requests and state changes (i.e. quit).
1388 timeout
= ( gRetryFirewall
) ? kRetryFirewallPeriod
: INFINITE
;
1392 HANDLE waitList
[ 3 ];
1394 waitList
[ 0 ] = gStopEvent
;
1395 waitList
[ 1 ] = gSPSWakeupEvent
;
1396 waitList
[ 2 ] = gSPSSleepEvent
;
1398 result
= WaitForMultipleObjects( 3, waitList
, FALSE
, timeout
);
1400 if ( result
== WAIT_OBJECT_0
)
1404 else if ( result
== WAIT_OBJECT_0
+ 1 )
1407 LARGE_INTEGER timeout
;
1409 dlog( kDebugLevelInfo
, DEBUG_NAME
"setting suspend event\n" );
1411 // Stay awake for 60 seconds
1413 temp
= -60 * 10000000;
1414 timeout
.LowPart
= (DWORD
) ( temp
& 0xFFFFFFFF );
1415 timeout
.HighPart
= (LONG
) ( temp
>> 32 );
1417 SetWaitableTimer( gSPSSleepEvent
, &timeout
, 0, NULL
, NULL
, TRUE
);
1419 else if ( result
== WAIT_OBJECT_0
+ 2 )
1421 dlog( kDebugLevelInfo
, DEBUG_NAME
"suspending machine\n" );
1422 SetSuspendState( FALSE
, FALSE
, FALSE
);
1424 else if ( result
== WAIT_TIMEOUT
)
1428 err
= CheckFirewall();
1435 // Unexpected wait result.
1436 dlog( kDebugLevelWarning
, DEBUG_NAME
"%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__
, result
);
1443 //===========================================================================================================================
1444 // ServiceSpecificStop
1445 //===========================================================================================================================
1447 static OSStatus
ServiceSpecificStop( void )
1452 ok
= SetEvent(gStopEvent
);
1453 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
1454 require_noerr( err
, exit
);
1459 //===========================================================================================================================
1460 // ServiceSpecificFinalize
1461 //===========================================================================================================================
1463 static void ServiceSpecificFinalize( int argc
, LPTSTR argv
[] )
1465 DEBUG_UNUSED( argc
);
1466 DEBUG_UNUSED( argv
);
1469 // clean up any open sessions
1471 while (gEventSources
.Head
)
1473 EventSourceFinalize((Win32EventSource
*) gEventSources
.Head
);
1476 // give a chance for the udsserver code to clean up
1481 // and finally close down the mDNSCore
1483 mDNS_Close(&gMDNSRecord
);
1486 // clean up the event sources mutex...no one should be using it now
1488 DeleteCriticalSection(&gEventSourceLock
);
1490 if ( gSPSWakeupEvent
)
1492 CloseHandle( gSPSWakeupEvent
);
1493 gSPSWakeupEvent
= NULL
;
1496 if ( gSPSSleepEvent
)
1498 CloseHandle( gSPSSleepEvent
);
1499 gSPSSleepEvent
= NULL
;
1504 CloseHandle( gStopEvent
);
1509 // clean up loaded library
1512 if( gIPHelperLibraryInstance
)
1514 gGetIpInterfaceEntryFunctionPtr
= NULL
;
1516 FreeLibrary( gIPHelperLibraryInstance
);
1517 gIPHelperLibraryInstance
= NULL
;
1523 CoreCallback(mDNS
* const inMDNS
, mStatus status
)
1525 if (status
== mStatus_ConfigChanged
)
1527 SetLLRoute( inMDNS
);
1533 udsIdle(mDNS
* const inMDNS
, mDNSs32 interval
)
1535 DEBUG_UNUSED( inMDNS
);
1538 // rdar://problem/3697326
1540 // udsserver_idle wasn't being locked. This resulted
1541 // in multiple threads contesting for the all_requests
1542 // data structure in uds_daemon.c
1544 mDNSPlatformLock(&gMDNSRecord
);
1546 interval
= udsserver_idle(interval
);
1548 mDNSPlatformUnlock(&gMDNSRecord
);
1555 HostDescriptionChanged(mDNS
* const inMDNS
)
1557 DEBUG_UNUSED( inMDNS
);
1559 udsserver_handle_configchange(inMDNS
);
1563 mDNSlocal
unsigned WINAPI
1564 udsSocketThread(LPVOID inParam
)
1566 Win32EventSource
* source
= (Win32EventSource
*) inParam
;
1567 DWORD threadID
= GetCurrentThreadId();
1572 bool locked
= false;
1575 waitCount
= source
->waitCount
;
1576 waitList
[0] = source
->waitList
[0];
1577 waitList
[1] = source
->waitList
[1];
1578 done
= (bool) (source
->flags
& EventSourceFinalized
);
1584 result
= WaitForMultipleObjects(waitCount
, waitList
, FALSE
, INFINITE
);
1586 mDNSPlatformLock(&gMDNSRecord
);
1589 // <rdar://problem/3838237>
1591 // Look up the source by the thread id. This will ensure that the
1592 // source is still extant. It could already have been deleted
1593 // by the processing thread.
1598 for (source
= gEventSources
.Head
; source
; source
= source
->next
)
1600 if (source
->threadID
== threadID
)
1606 EventSourceUnlock();
1616 if (result
== WAIT_OBJECT_0
)
1618 source
->callback( (int) source
->sock
, 0, source
->context
);
1623 else if (result
== WAIT_OBJECT_0
+ 1)
1626 // this is a bit of a hack. we want to clean up the internal data structures
1627 // so we'll go in here and it will clean up for us
1629 shutdown(source
->sock
, 2);
1630 source
->callback( (int) source
->sock
, 0, source
->context
);
1636 // Unexpected wait result.
1637 dlog( kDebugLevelWarning
, DEBUG_NAME
"%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__
, result
);
1641 done
= (bool) (source
->flags
& EventSourceFinalized
);
1643 mDNSPlatformUnlock(&gMDNSRecord
);
1648 source
->flags
|= EventSourceFlagsThreadDone
;
1649 safeToClose
= !( source
->flags
& EventSourceFlagsNoClose
);
1650 EventSourceUnlock();
1654 EventSourceFinalize( source
);
1661 mDNSPlatformUnlock(&gMDNSRecord
);
1664 _endthreadex_compat( (unsigned) err
);
1665 return( (unsigned) err
);
1670 udsSupportAddFDToEventLoop( SocketRef fd
, udsEventCallback callback
, void *context
)
1672 Win32EventSource
* newSource
;
1676 newSource
= malloc(sizeof(Win32EventSource
));
1677 require_action( newSource
, exit
, err
= mStatus_NoMemoryErr
);
1678 mDNSPlatformMemZero(newSource
, sizeof(Win32EventSource
));
1680 newSource
->flags
= 0;
1681 newSource
->sock
= (SOCKET
) fd
;
1682 newSource
->callback
= callback
;
1683 newSource
->context
= context
;
1685 newSource
->socketEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1686 err
= translate_errno( newSource
->socketEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1687 require_noerr( err
, exit
);
1689 newSource
->closeEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1690 err
= translate_errno( newSource
->closeEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1691 require_noerr( err
, exit
);
1693 err
= WSAEventSelect(newSource
->sock
, newSource
->socketEvent
, FD_ACCEPT
|FD_READ
|FD_CLOSE
);
1694 err
= translate_errno( err
== 0, errno_compat(), kNoResourcesErr
);
1695 require_noerr( err
, exit
);
1697 newSource
->waitCount
= 0;
1698 newSource
->waitList
[ newSource
->waitCount
++ ] = newSource
->socketEvent
;
1699 newSource
->waitList
[ newSource
->waitCount
++ ] = newSource
->closeEvent
;
1706 // add the event source to the end of the list, while checking
1707 // to see if the list needs to be initialized
1709 if ( gEventSources
.LinkOffset
== 0)
1711 InitLinkedList( &gEventSources
, offsetof( Win32EventSource
, next
));
1714 AddToTail( &gEventSources
, newSource
);
1717 // no longer using the list
1719 EventSourceUnlock();
1721 // Create thread with _beginthreadex() instead of CreateThread() to avoid memory leaks when using static run-time
1722 // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
1723 // Create the thread suspended then resume it so the thread handle and ID are valid before the thread starts running.
1724 newSource
->threadHandle
= (HANDLE
) _beginthreadex_compat( NULL
, 0, udsSocketThread
, newSource
, CREATE_SUSPENDED
, &newSource
->threadID
);
1725 err
= translate_errno( newSource
->threadHandle
, (mStatus
) GetLastError(), kUnknownErr
);
1726 require_noerr( err
, exit
);
1728 result
= ResumeThread( newSource
->threadHandle
);
1729 err
= translate_errno( result
!= (DWORD
) -1, errno_compat(), kNoResourcesErr
);
1730 require_noerr( err
, exit
);
1734 if (err
&& newSource
)
1736 EventSourceFinalize(newSource
);
1744 udsSupportRemoveFDFromEventLoop( SocketRef fd
) // Note: This also CLOSES the socket
1746 Win32EventSource
* source
;
1747 mStatus err
= mStatus_NoError
;
1750 // find the event source
1754 for (source
= gEventSources
.Head
; source
; source
= source
->next
)
1756 if (source
->sock
== (SOCKET
) fd
)
1763 // if we found him, finalize him
1767 EventSourceFinalize(source
);
1771 // done with the list
1773 EventSourceUnlock();
1781 mDNSexport
void RecordUpdatedNiceLabel(mDNS
*const m
, mDNSs32 delay
)
1790 EventSourceFinalize(Win32EventSource
* source
)
1794 Win32EventSource
* inserted
;
1803 // Find the session in the list.
1808 for( inserted
= (Win32EventSource
*) gEventSources
.Head
; inserted
; inserted
= inserted
->next
)
1810 if( inserted
== source
)
1815 require_action( inserted
, exit
, err
= kNotFoundErr
);
1818 // note that we've had finalize called
1820 source
->flags
|= EventSourceFinalized
;
1822 // If we're being called from the same thread as the session (e.g. message callback is closing the session) then
1823 // we must defer the close until the thread is done because the thread is still using the session object.
1826 threadID
= GetCurrentThreadId();
1827 sameThread
= source
->threadHandle
&& ( threadID
== source
->threadID
);
1828 if( sameThread
&& !( source
->flags
& EventSourceFlagsThreadDone
) )
1830 source
->flags
&= ~EventSourceFlagsNoClose
;
1834 // If the thread we're not being called from the session thread, but the thread has already marked itself as
1835 // as done (e.g. session closed from something like a peer disconnect and at the same time the client also
1836 // tried to close) then we only want to continue with the close if the thread is not going to close itself.
1838 if( !sameThread
&& ( source
->flags
& EventSourceFlagsThreadDone
) && !( source
->flags
& EventSourceFlagsNoClose
) )
1843 // Signal a close so the thread exits.
1845 if( source
->closeEvent
)
1847 ok
= SetEvent( source
->closeEvent
);
1848 check_translated_errno( ok
, errno_compat(), kUnknownErr
);
1856 source
->flags
|= EventSourceFlagsNoClose
;
1858 // Remove the session from the list.
1859 RemoveFromList(&gEventSources
, source
);
1861 EventSourceUnlock();
1864 // Wait for the thread to exit. Give up after 3 seconds to handle a hung thread.
1866 if( source
->threadHandle
&& ( threadID
!= source
->threadID
) )
1868 result
= WaitForSingleObject( source
->threadHandle
, 3 * 1000 );
1869 check_translated_errno( result
== WAIT_OBJECT_0
, (OSStatus
) GetLastError(), result
);
1872 // Release the thread.
1874 if( source
->threadHandle
)
1876 ok
= CloseHandle( source
->threadHandle
);
1877 check_translated_errno( ok
, errno_compat(), kUnknownErr
);
1878 source
->threadHandle
= NULL
;
1881 // Release the socket event.
1883 if( source
->socketEvent
)
1885 ok
= CloseHandle( source
->socketEvent
);
1886 check_translated_errno( ok
, errno_compat(), kUnknownErr
);
1887 source
->socketEvent
= NULL
;
1890 // Release the close event.
1892 if( source
->closeEvent
)
1894 ok
= CloseHandle( source
->closeEvent
);
1895 check_translated_errno( ok
, errno_compat(), kUnknownErr
);
1896 source
->closeEvent
= NULL
;
1899 // Release the memory used by the object.
1904 dlog( kDebugLevelNotice
, DEBUG_NAME
"session closed\n" );
1910 EventSourceUnlock();
1920 EnterCriticalSection(&gEventSourceLock
);
1927 LeaveCriticalSection(&gEventSourceLock
);
1931 //===========================================================================================================================
1932 // SystemWakeForNetworkAccess
1933 //===========================================================================================================================
1936 SystemWakeForNetworkAccess( LARGE_INTEGER
* timeout
)
1942 SYSTEM_POWER_STATUS powerStatus
;
1944 time_t nextWakeupTime
;
1949 dlog( kDebugLevelInfo
, DEBUG_NAME
"SystemWakeForNetworkAccess\n" );
1951 // Make sure we have a timer
1953 require_action( gSPSWakeupEvent
!= NULL
, exit
, ok
= FALSE
);
1954 require_action( gSPSSleepEvent
!= NULL
, exit
, ok
= FALSE
);
1956 // Make sure the user enabled bonjour sleep proxy client
1958 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode L
"\\Power Management", &key
);
1959 require_action( !err
, exit
, ok
= FALSE
);
1960 dwSize
= sizeof( DWORD
);
1961 err
= RegQueryValueEx( key
, L
"Enabled", NULL
, NULL
, (LPBYTE
) &enabled
, &dwSize
);
1962 require_action( !err
, exit
, ok
= FALSE
);
1963 require_action( enabled
, exit
, ok
= FALSE
);
1965 // Make sure machine is on AC power
1967 ok
= ( mDNSu8
) GetSystemPowerStatus( &powerStatus
);
1968 require_action( ok
, exit
, ok
= FALSE
);
1969 require_action( powerStatus
.ACLineStatus
== AC_LINE_ONLINE
, exit
, ok
= FALSE
);
1971 // Now make sure we have a network interface that does wake-on-lan
1973 UpdateWOMPConfig( &gMDNSRecord
);
1974 require_action( gMDNSRecord
.p
->womp
, exit
, ok
= FALSE
);
1976 // Calculate next wake up time
1978 startTime
= time( NULL
);
1979 nextWakeupTime
= startTime
+ ( 120 * 60 );
1981 if ( gMDNSRecord
.p
->nextDHCPLeaseExpires
< nextWakeupTime
)
1983 nextWakeupTime
= gMDNSRecord
.p
->nextDHCPLeaseExpires
;
1986 // Finally calculate the next relative wakeup time
1988 delta
= ( time_t ) ( ( ( double )( nextWakeupTime
- startTime
) ) * 0.9 );
1989 delta64
= -delta
* 10000000;
1990 timeout
->LowPart
= (DWORD
) ( delta64
& 0xFFFFFFFF );
1991 timeout
->HighPart
= (LONG
) ( delta64
>> 32 );
1993 dlog( kDebugLevelInfo
, DEBUG_NAME
"enabling sleep proxy client with next wakeup time %d seconds from now\n", delta
);
2008 //===========================================================================================================================
2010 //===========================================================================================================================
2013 HaveRoute( PMIB_IPFORWARDROW rowExtant
, unsigned long addr
, unsigned long metric
)
2015 PMIB_IPFORWARDTABLE pIpForwardTable
= NULL
;
2017 BOOL bOrder
= FALSE
;
2020 unsigned long int i
;
2023 // Find out how big our buffer needs to be.
2025 err
= GetIpForwardTable(NULL
, &dwSize
, bOrder
);
2026 require_action( err
== ERROR_INSUFFICIENT_BUFFER
, exit
, err
= kUnknownErr
);
2029 // Allocate the memory for the table
2031 pIpForwardTable
= (PMIB_IPFORWARDTABLE
) malloc( dwSize
);
2032 require_action( pIpForwardTable
, exit
, err
= kNoMemoryErr
);
2035 // Now get the table.
2037 err
= GetIpForwardTable(pIpForwardTable
, &dwSize
, bOrder
);
2038 require_noerr( err
, exit
);
2041 // Search for the row in the table we want.
2043 for ( i
= 0; i
< pIpForwardTable
->dwNumEntries
; i
++)
2045 if ( ( pIpForwardTable
->table
[i
].dwForwardDest
== addr
) && ( !metric
|| ( pIpForwardTable
->table
[i
].dwForwardMetric1
== metric
) ) )
2047 memcpy( rowExtant
, &(pIpForwardTable
->table
[i
]), sizeof(*rowExtant
) );
2055 if ( pIpForwardTable
!= NULL
)
2057 free(pIpForwardTable
);
2064 //===========================================================================================================================
2066 //===========================================================================================================================
2069 IsValidAddress( const char * addr
)
2071 return ( addr
&& ( strcmp( addr
, "0.0.0.0" ) != 0 ) ) ? true : false;
2075 //===========================================================================================================================
2076 // GetAdditionalMetric
2077 //===========================================================================================================================
2080 GetAdditionalMetric( DWORD ifIndex
)
2084 if( !gIPHelperLibraryInstance
)
2086 gIPHelperLibraryInstance
= LoadLibrary( TEXT( "Iphlpapi" ) );
2088 gGetIpInterfaceEntryFunctionPtr
=
2089 (GetIpInterfaceEntryFunctionPtr
) GetProcAddress( gIPHelperLibraryInstance
, "GetIpInterfaceEntry" );
2091 if( !gGetIpInterfaceEntryFunctionPtr
)
2095 ok
= FreeLibrary( gIPHelperLibraryInstance
);
2096 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
2097 gIPHelperLibraryInstance
= NULL
;
2101 if ( gGetIpInterfaceEntryFunctionPtr
)
2103 MIB_IPINTERFACE_ROW row
;
2106 ZeroMemory( &row
, sizeof( MIB_IPINTERFACE_ROW
) );
2107 row
.Family
= AF_INET
;
2108 row
.InterfaceIndex
= ifIndex
;
2109 err
= gGetIpInterfaceEntryFunctionPtr( &row
);
2110 require_noerr( err
, exit
);
2111 metric
= row
.Metric
+ 256;
2120 //===========================================================================================================================
2122 //===========================================================================================================================
2125 SetLLRoute( mDNS
* const inMDNS
)
2127 OSStatus err
= kNoErr
;
2129 DEBUG_UNUSED( inMDNS
);
2132 // <rdar://problem/4096464> Don't call SetLLRoute on loopback
2133 // <rdar://problem/6885843> Default route on Windows 7 breaks network connectivity
2135 // Don't mess w/ the routing table on Vista and later OSes, as
2136 // they have a permanent route to link-local addresses. Otherwise,
2137 // set a route to link local addresses (169.254.0.0)
2139 if ( ( gOSMajorVersion
< 6 ) && gServiceManageLLRouting
&& !gPlatformStorage
.registeredLoopback4
)
2142 MIB_IPFORWARDROW rowExtant
;
2144 MIB_IPFORWARDROW row
;
2146 ZeroMemory(&row
, sizeof(row
));
2148 err
= GetRouteDestination(&ifIndex
, &row
.dwForwardNextHop
);
2149 require_noerr( err
, exit
);
2150 row
.dwForwardDest
= inet_addr(kLLNetworkAddr
);
2151 row
.dwForwardIfIndex
= ifIndex
;
2152 row
.dwForwardMask
= inet_addr(kLLNetworkAddrMask
);
2153 row
.dwForwardType
= 3;
2154 row
.dwForwardProto
= MIB_IPPROTO_NETMGMT
;
2155 row
.dwForwardAge
= 0;
2156 row
.dwForwardPolicy
= 0;
2157 row
.dwForwardMetric1
= 20 + GetAdditionalMetric( ifIndex
);
2158 row
.dwForwardMetric2
= (DWORD
) - 1;
2159 row
.dwForwardMetric3
= (DWORD
) - 1;
2160 row
.dwForwardMetric4
= (DWORD
) - 1;
2161 row
.dwForwardMetric5
= (DWORD
) - 1;
2166 // check to make sure we don't already have a route
2168 if ( HaveRoute( &rowExtant
, inet_addr( kLLNetworkAddr
), 0 ) )
2171 // set the age to 0 so that we can do a memcmp.
2173 rowExtant
.dwForwardAge
= 0;
2176 // check to see if this route is the same as our route
2178 if (memcmp(&row
, &rowExtant
, sizeof(row
)) != 0)
2181 // if it isn't then delete this entry
2183 DeleteIpForwardEntry(&rowExtant
);
2188 // else it is, so we don't want to create another route
2194 if (addRoute
&& row
.dwForwardNextHop
)
2196 err
= CreateIpForwardEntry(&row
);
2207 //===========================================================================================================================
2208 // GetRouteDestination
2209 //===========================================================================================================================
2212 GetRouteDestination(DWORD
* ifIndex
, DWORD
* address
)
2215 IP_ADAPTER_INFO
* pAdapterInfo
= NULL
;
2216 IP_ADAPTER_INFO
* pAdapter
= NULL
;
2218 mDNSBool done
= mDNSfalse
;
2222 // GetBestInterface will fail if there is no default gateway
2223 // configured. If that happens, we will just take the first
2224 // interface in the list. MSDN support says there is no surefire
2225 // way to manually determine what the best interface might
2226 // be for a particular network address.
2228 ia
.s_addr
= inet_addr(kLLNetworkAddr
);
2229 err
= GetBestInterface(*(IPAddr
*) &ia
, ifIndex
);
2237 // Make an initial call to GetAdaptersInfo to get
2238 // the necessary size into the bufLen variable
2240 err
= GetAdaptersInfo( NULL
, &bufLen
);
2241 require_action( err
== ERROR_BUFFER_OVERFLOW
, exit
, err
= kUnknownErr
);
2243 pAdapterInfo
= (IP_ADAPTER_INFO
*) malloc( bufLen
);
2244 require_action( pAdapterInfo
, exit
, err
= kNoMemoryErr
);
2246 err
= GetAdaptersInfo( pAdapterInfo
, &bufLen
);
2247 require_noerr( err
, exit
);
2249 pAdapter
= pAdapterInfo
;
2252 // <rdar://problem/3718122>
2253 // <rdar://problem/5652098>
2255 // Look for the Nortel VPN virtual interface, along with Juniper virtual interface.
2257 // If these interfaces are active (i.e., has a non-zero IP Address),
2258 // then we want to disable routing table modifications.
2262 if ( ( IsNortelVPN( pAdapter
) || IsJuniperVPN( pAdapter
) || IsCiscoVPN( pAdapter
) ) &&
2263 ( inet_addr( pAdapter
->IpAddressList
.IpAddress
.String
) != 0 ) )
2265 dlog( kDebugLevelTrace
, DEBUG_NAME
"disabling routing table management due to VPN incompatibility" );
2269 pAdapter
= pAdapter
->Next
;
2274 pAdapter
= pAdapterInfo
;
2279 // If we don't have an interface selected, choose the first one that is of type ethernet and
2280 // has a valid IP Address
2282 if ((pAdapter
->Type
== MIB_IF_TYPE_ETHERNET
) && ( IsValidAddress( pAdapter
->IpAddressList
.IpAddress
.String
) ) && (!(*ifIndex
) || (pAdapter
->Index
== (*ifIndex
))))
2284 *address
= inet_addr( pAdapter
->IpAddressList
.IpAddress
.String
);
2285 *ifIndex
= pAdapter
->Index
;
2290 pAdapter
= pAdapter
->Next
;
2293 // If we found the right interface, or we weren't trying to find a specific interface then we're done
2295 if ( !err
|| !( *ifIndex
) )
2300 // Otherwise, try again by wildcarding the interface
2310 if ( pAdapterInfo
!= NULL
)
2312 free( pAdapterInfo
);
2320 IsNortelVPN( IP_ADAPTER_INFO
* pAdapter
)
2322 return ((pAdapter
->Type
== MIB_IF_TYPE_ETHERNET
) &&
2323 (pAdapter
->AddressLength
== 6) &&
2324 (pAdapter
->Address
[0] == 0x44) &&
2325 (pAdapter
->Address
[1] == 0x45) &&
2326 (pAdapter
->Address
[2] == 0x53) &&
2327 (pAdapter
->Address
[3] == 0x54) &&
2328 (pAdapter
->Address
[4] == 0x42) &&
2329 (pAdapter
->Address
[5] == 0x00)) ? true : false;
2334 IsJuniperVPN( IP_ADAPTER_INFO
* pAdapter
)
2336 return ( strnistr( pAdapter
->Description
, "Juniper", sizeof( pAdapter
->Description
) ) != NULL
) ? true : false;
2341 IsCiscoVPN( IP_ADAPTER_INFO
* pAdapter
)
2343 return ((pAdapter
->Type
== MIB_IF_TYPE_ETHERNET
) &&
2344 (pAdapter
->AddressLength
== 6) &&
2345 (pAdapter
->Address
[0] == 0x00) &&
2346 (pAdapter
->Address
[1] == 0x05) &&
2347 (pAdapter
->Address
[2] == 0x9a) &&
2348 (pAdapter
->Address
[3] == 0x3c) &&
2349 (pAdapter
->Address
[4] == 0x7a) &&
2350 (pAdapter
->Address
[5] == 0x00)) ? true : false;
2355 strnistr( const char * string
, const char * subString
, size_t max
)
2357 size_t subStringLen
;
2363 if ( ( string
== NULL
) || ( subString
== NULL
) )
2368 stringLen
= ( max
> strlen( string
) ) ? strlen( string
) : max
;
2370 if ( stringLen
== 0 )
2375 subStringLen
= strlen( subString
);
2377 if ( subStringLen
== 0 )
2382 if ( subStringLen
> stringLen
)
2387 maxOffset
= stringLen
- subStringLen
;
2390 for ( offset
= 0; offset
<= maxOffset
; offset
++ )
2392 if ( _strnicmp( pPos
, subString
, subStringLen
) == 0 )