2 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 Change History (most recent first):
26 Revision 1.38 2005/10/05 20:55:15 herscher
27 <rdar://problem/4096464> Don't call SetLLRoute on loopback interface
29 Revision 1.37 2005/10/05 18:05:28 herscher
30 <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.
32 Revision 1.36 2005/09/11 22:12:42 herscher
33 <rdar://problem/4247793> Remove dependency on WMI. Ensure that the Windows firewall is turned on before trying to configure it.
35 Revision 1.35 2005/06/30 18:29:49 shersche
36 <rdar://problem/4090059> Don't overwrite the localized service description text
38 Revision 1.34 2005/04/22 07:34:23 shersche
39 Check an interface's address and make sure it's valid before using it to set link-local routes.
41 Revision 1.33 2005/04/13 17:48:23 shersche
42 <rdar://problem/4079667> Make sure there is only one default route for link-local addresses.
44 Revision 1.32 2005/04/06 01:32:05 shersche
45 Remove default route for link-local addressing when another interface comes up with a routable IPv4 address
47 Revision 1.31 2005/04/06 01:00:11 shersche
48 <rdar://problem/4080127> GetFullPathName() should be passed the number of TCHARs in the path buffer, not the size in bytes of the path buffer.
50 Revision 1.30 2005/04/06 00:52:43 shersche
51 <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.
53 Revision 1.29 2005/03/06 05:21:56 shersche
54 <rdar://problem/4037635> Fix corrupt UTF-8 name when non-ASCII system name used, enabled unicode support
56 Revision 1.28 2005/03/03 02:27:24 shersche
57 Include the RegNames.h header file for names of registry keys
59 Revision 1.27 2005/03/02 20:12:59 shersche
62 Revision 1.26 2005/02/15 08:00:27 shersche
63 <rdar://problem/4007151> Update name
65 Revision 1.25 2005/02/10 22:35:36 cheshire
66 <rdar://problem/3727944> Update name
68 Revision 1.24 2005/01/27 20:02:43 cheshire
69 udsSupportRemoveFDFromEventLoop() needs to close the SocketRef as well
71 Revision 1.23 2005/01/25 08:14:15 shersche
72 Change CacheRecord to CacheEntity
74 Revision 1.22 2004/12/10 13:18:40 cheshire
75 Create no-op function RecordUpdatedNiceLabel(), required by uds_daemon.c
77 Revision 1.21 2004/11/10 04:03:41 shersche
78 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.
80 Revision 1.20 2004/10/14 21:44:05 shersche
81 <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.
84 Revision 1.19 2004/10/12 17:59:55 shersche
85 <rdar://problem/3718122> Disable routing table modifications when Nortel VPN adapter is active
88 Revision 1.18 2004/10/11 21:57:50 shersche
89 <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.
92 Revision 1.17 2004/09/17 01:08:58 cheshire
93 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
94 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
95 declared in that file are ONLY appropriate to single-address-space embedded applications.
96 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
98 Revision 1.16 2004/09/16 18:49:34 shersche
99 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.
101 Revision 1.15 2004/09/15 17:13:33 shersche
104 Revision 1.14 2004/09/15 09:37:25 shersche
105 Add SharedAccess to dependency list, call CheckFirewall after sending status back to SCM
107 Revision 1.13 2004/09/13 07:35:10 shersche
108 <rdar://problem/3762235> Add mDNSResponder to Windows Firewall application list if SP2 is detected and app hasn't been added before
111 Revision 1.12 2004/09/11 21:18:32 shersche
112 <rdar://problem/3779502> Add route to ARP everything when a 169.254.x.x address is selected
115 Revision 1.11 2004/09/11 05:39:19 shersche
116 <rdar://problem/3780203> Detect power managment state changes, calling mDNSCoreMachineSleep(m, true) on sleep, and mDNSCoreMachineSleep(m, false) on resume
119 Revision 1.10 2004/08/16 21:45:24 shersche
120 Use the full pathname of executable when calling CreateService()
121 Submitted by: prepin@zetron.com
123 Revision 1.9 2004/08/11 01:59:41 cheshire
124 Remove "mDNS *globalInstance" parameter from udsserver_init()
126 Revision 1.8 2004/08/05 05:40:05 shersche
127 <rdar://problem/3751566> Only invoke SetConsoleCtrlHandler when running directly from command line.
128 <rdar://problem/3751481> Invoke udsserver_handle_configchange() when the computer description changes
129 Bug #: 3751481, 3751566
131 Revision 1.7 2004/07/26 05:35:07 shersche
132 ignore non-enet interfaces when setting up link-local routing
134 Revision 1.6 2004/07/20 06:48:26 shersche
135 <rdar://problem/3718122> Allow registry entries to dictate whether to manage link local routing
138 Revision 1.5 2004/07/09 19:08:07 shersche
139 <rdar://problem/3713762> ServiceSetupEventLogging() errors are handled gracefully
142 Revision 1.4 2004/06/24 20:58:15 shersche
143 Fix compiler error in Release build
144 Submitted by: herscher
146 Revision 1.3 2004/06/24 15:28:53 shersche
147 Automatically setup routes to link-local addresses upon interface list change events.
148 Submitted by: herscher
150 Revision 1.2 2004/06/23 16:56:00 shersche
151 <rdar://problem/3697326> locked call to udsserver_idle().
153 Submitted by: herscher
155 Revision 1.1 2004/06/18 04:16:41 rpantos
158 Revision 1.1 2004/01/30 02:58:39 bradley
159 mDNSResponder Windows Service. Provides global Bonjour support with an IPC interface.
167 #include "CommonServices.h"
168 #include "DebugServices.h"
169 #include "RegNames.h"
171 #include "uds_daemon.h"
172 #include "GenLinkedList.h"
174 #include "Resource.h"
176 #include "mDNSEmbeddedAPI.h"
177 #include "mDNSWin32.h"
179 #include "Firewall.h"
181 #if( !TARGET_OS_WINDOWS_CE )
184 #include <ipExport.h>
185 #include <iphlpapi.h>
190 #pragma mark == Constants ==
193 //===========================================================================================================================
195 //===========================================================================================================================
197 #define DEBUG_NAME "[Server] "
198 #define kServiceFirewallName L"Bonjour"
199 #define kServiceDependencies TEXT("Tcpip\0\0")
200 #define kDNSServiceCacheEntryCountDefault 512
201 #define kRetryFirewallPeriod 30 * 1000
203 #define RR_CACHE_SIZE 500
204 static CacheEntity gRRCache
[RR_CACHE_SIZE
];
206 #pragma mark == Structures ==
209 //===========================================================================================================================
211 //===========================================================================================================================
212 //---------------------------------------------------------------------------------------------------------------------------
213 /*! @typedef EventSourceFlags
215 @abstract Session flags.
217 @constant EventSourceFlagsNone No flags.
218 @constant EventSourceFlagsThreadDone Thread is no longer active.
219 @constant EventSourceFlagsNoClose Do not close the session when the thread exits.
220 @constant EventSourceFinalized Finalize has been called for this session
223 typedef uint32_t EventSourceFlags
;
225 #define EventSourceFlagsNone 0
226 #define EventSourceFlagsThreadDone ( 1 << 2 )
227 #define EventSourceFlagsNoClose ( 1 << 3 )
228 #define EventSourceFinalized ( 1 << 4 )
231 typedef struct Win32EventSource
233 EventSourceFlags flags
;
238 udsEventCallback callback
;
243 struct Win32EventSource
* next
;
248 #pragma mark == Prototypes ==
251 //===========================================================================================================================
253 //===========================================================================================================================
255 int __cdecl
wmain( int argc
, LPTSTR argv
[] );
257 int __cdecl
main( int argc
, char *argv
[] );
259 static void Usage( void );
260 static BOOL WINAPI
ConsoleControlHandler( DWORD inControlEvent
);
261 static OSStatus
InstallService( LPCTSTR inName
, LPCTSTR inDisplayName
, LPCTSTR inDescription
, LPCTSTR inPath
);
262 static OSStatus
RemoveService( LPCTSTR inName
);
263 static OSStatus
SetServiceParameters();
264 static OSStatus
GetServiceParameters();
265 static OSStatus
CheckFirewall();
266 static OSStatus
SetServiceInfo( SC_HANDLE inSCM
, LPCTSTR inServiceName
, LPCTSTR inDescription
);
267 static void ReportStatus( int inType
, const char *inFormat
, ... );
268 static OSStatus
RunDirect( int argc
, LPTSTR argv
[] );
270 static void WINAPI
ServiceMain( DWORD argc
, LPTSTR argv
[] );
271 static OSStatus
ServiceSetupEventLogging( void );
272 static DWORD WINAPI
ServiceControlHandler( DWORD inControl
, DWORD inEventType
, LPVOID inEventData
, LPVOID inContext
);
274 static OSStatus
ServiceRun( int argc
, LPTSTR argv
[] );
275 static void ServiceStop( void );
277 static OSStatus
ServiceSpecificInitialize( int argc
, LPTSTR argv
[] );
278 static OSStatus
ServiceSpecificRun( int argc
, LPTSTR argv
[] );
279 static OSStatus
ServiceSpecificStop( void );
280 static void ServiceSpecificFinalize( int argc
, LPTSTR argv
[] );
281 static mStatus
EventSourceFinalize(Win32EventSource
* source
);
282 static void EventSourceLock();
283 static void EventSourceUnlock();
284 static mDNSs32
udsIdle(mDNS
* const inMDNS
, mDNSs32 interval
);
285 static void CoreCallback(mDNS
* const inMDNS
, mStatus result
);
286 static void HostDescriptionChanged(mDNS
* const inMDNS
);
287 static OSStatus
GetRouteDestination(DWORD
* ifIndex
, DWORD
* address
);
288 static OSStatus
SetLLRoute( mDNS
* const inMDNS
);
289 static bool HaveRoute( PMIB_IPFORWARDROW rowExtant
, unsigned long addr
);
290 static bool IsValidAddress( const char * addr
);
293 # define StrLen(X) wcslen(X)
294 # define StrCmp(X,Y) wcscmp(X,Y)
296 # define StrLen(X) strlen(X)
297 # define StrCmp(X,Y) strcmp(X,Y)
301 #define kLLNetworkAddr "169.254.0.0"
302 #define kLLNetworkAddrMask "255.255.0.0"
305 #include "mDNSEmbeddedAPI.h"
308 #pragma mark == Globals ==
311 //===========================================================================================================================
313 //===========================================================================================================================
314 #define gMDNSRecord mDNSStorage
315 DEBUG_LOCAL mDNS_PlatformSupport gPlatformStorage
;
316 DEBUG_LOCAL BOOL gServiceQuietMode
= FALSE
;
317 DEBUG_LOCAL SERVICE_TABLE_ENTRY gServiceDispatchTable
[] =
319 { kServiceName
, ServiceMain
},
322 DEBUG_LOCAL SERVICE_STATUS gServiceStatus
;
323 DEBUG_LOCAL SERVICE_STATUS_HANDLE gServiceStatusHandle
= NULL
;
324 DEBUG_LOCAL HANDLE gServiceEventSource
= NULL
;
325 DEBUG_LOCAL
bool gServiceAllowRemote
= false;
326 DEBUG_LOCAL
int gServiceCacheEntryCount
= 0; // 0 means to use the DNS-SD default.
327 DEBUG_LOCAL
bool gServiceManageLLRouting
= true;
328 DEBUG_LOCAL
int gWaitCount
= 0;
329 DEBUG_LOCAL HANDLE
* gWaitList
= NULL
;
330 DEBUG_LOCAL HANDLE gStopEvent
= NULL
;
331 DEBUG_LOCAL CRITICAL_SECTION gEventSourceLock
;
332 DEBUG_LOCAL GenLinkedList gEventSources
;
333 DEBUG_LOCAL BOOL gRetryFirewall
= FALSE
;
340 //===========================================================================================================================
342 //===========================================================================================================================
344 int __cdecl
wmain( int argc
, wchar_t * argv
[] )
346 int __cdecl
main( int argc
, char *argv
[] )
354 debug_initialize( kDebugOutputTypeMetaConsole
);
355 debug_set_property( kDebugPropertyTagPrintLevel
, kDebugLevelVerbose
);
357 // Default to automatically starting the service dispatcher if no extra arguments are specified.
359 start
= ( argc
<= 1 );
363 for( i
= 1; i
< argc
; ++i
)
365 if( StrCmp( argv
[ i
], TEXT("-install") ) == 0 ) // Install
370 LoadString( GetModuleHandle( NULL
), IDS_SERVICE_DESCRIPTION
, desc
, sizeof( desc
) );
371 err
= InstallService( kServiceName
, kServiceName
, desc
, argv
[0] );
374 ReportStatus( EVENTLOG_ERROR_TYPE
, "install service failed (%d)\n", err
);
378 else if( StrCmp( argv
[ i
], TEXT("-remove") ) == 0 ) // Remove
380 err
= RemoveService( kServiceName
);
383 ReportStatus( EVENTLOG_ERROR_TYPE
, "remove service failed (%d)\n", err
);
387 else if( StrCmp( argv
[ i
], TEXT("-start") ) == 0 ) // Start
391 else if( StrCmp( argv
[ i
], TEXT("-server") ) == 0 ) // Server
393 err
= RunDirect( argc
, argv
);
396 ReportStatus( EVENTLOG_ERROR_TYPE
, "run service directly failed (%d)\n", err
);
400 else if( StrCmp( argv
[ i
], TEXT("-q") ) == 0 ) // Quiet Mode (toggle)
402 gServiceQuietMode
= !gServiceQuietMode
;
404 else if( ( StrCmp( argv
[ i
], TEXT("-help") ) == 0 ) || // Help
405 ( StrCmp( argv
[ i
], TEXT("-h") ) == 0 ) )
419 // Start the service dispatcher if requested. This does not return until all services have terminated. If any
420 // global initialization is needed, it should be done before starting the service dispatcher, but only if it
421 // will take less than 30 seconds. Otherwise, use a separate thread for it and start the dispatcher immediately.
425 ok
= StartServiceCtrlDispatcher( gServiceDispatchTable
);
426 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kInUseErr
);
429 ReportStatus( EVENTLOG_ERROR_TYPE
, "start service dispatcher failed (%d)\n", err
);
436 dlog( kDebugLevelTrace
, DEBUG_NAME
"exited (%d %m)\n", err
, err
);
440 //===========================================================================================================================
442 //===========================================================================================================================
444 static void Usage( void )
446 fprintf( stderr
, "\n" );
447 fprintf( stderr
, "mDNSResponder 1.0d1\n" );
448 fprintf( stderr
, "\n" );
449 fprintf( stderr
, " <no args> Runs the service normally\n" );
450 fprintf( stderr
, " -install Creates the service and starts it\n" );
451 fprintf( stderr
, " -remove Stops the service and deletes it\n" );
452 fprintf( stderr
, " -start Starts the service dispatcher after processing all other arguments\n" );
453 fprintf( stderr
, " -server Runs the service directly as a server (for debugging)\n" );
454 fprintf( stderr
, " -q Toggles Quiet Mode (no events or output)\n" );
455 fprintf( stderr
, " -remote Allow remote connections\n" );
456 fprintf( stderr
, " -cache n Number of mDNS cache entries (defaults to %d)\n", kDNSServiceCacheEntryCountDefault
);
457 fprintf( stderr
, " -h[elp] Display Help/Usage\n" );
458 fprintf( stderr
, "\n" );
461 //===========================================================================================================================
462 // ConsoleControlHandler
463 //===========================================================================================================================
465 static BOOL WINAPI
ConsoleControlHandler( DWORD inControlEvent
)
471 switch( inControlEvent
)
474 case CTRL_BREAK_EVENT
:
475 case CTRL_CLOSE_EVENT
:
476 case CTRL_LOGOFF_EVENT
:
477 case CTRL_SHUTDOWN_EVENT
:
478 err
= ServiceSpecificStop();
479 require_noerr( err
, exit
);
492 //===========================================================================================================================
494 //===========================================================================================================================
496 static OSStatus
InstallService( LPCTSTR inName
, LPCTSTR inDisplayName
, LPCTSTR inDescription
, LPCTSTR inPath
)
502 TCHAR fullPath
[ MAX_PATH
];
509 // Get a full path to the executable since a relative path may have been specified.
511 size
= GetFullPathName( inPath
, MAX_PATH
, fullPath
, &namePtr
);
512 err
= translate_errno( size
> 0, (OSStatus
) GetLastError(), kPathErr
);
513 require_noerr( err
, exit
);
515 // Create the service and start it.
517 scm
= OpenSCManager( NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
518 err
= translate_errno( scm
, (OSStatus
) GetLastError(), kOpenErr
);
519 require_noerr( err
, exit
);
521 service
= CreateService( scm
, inName
, inDisplayName
, SERVICE_ALL_ACCESS
, SERVICE_WIN32_SHARE_PROCESS
,
522 SERVICE_AUTO_START
, SERVICE_ERROR_NORMAL
, fullPath
, NULL
, NULL
, kServiceDependencies
,
524 err
= translate_errno( service
, (OSStatus
) GetLastError(), kDuplicateErr
);
525 require_noerr( err
, exit
);
527 err
= SetServiceParameters();
532 err
= SetServiceInfo( scm
, inName
, inDescription
);
536 ok
= StartService( service
, 0, NULL
);
537 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kInUseErr
);
538 require_noerr( err
, exit
);
540 ReportStatus( EVENTLOG_SUCCESS
, "installed service \"%s\"/\"%s\" at \"%s\"\n", inName
, inDisplayName
, inPath
);
546 CloseServiceHandle( service
);
550 CloseServiceHandle( scm
);
555 //===========================================================================================================================
557 //===========================================================================================================================
559 static OSStatus
RemoveService( LPCTSTR inName
)
565 SERVICE_STATUS status
;
570 // Open a connection to the service.
572 scm
= OpenSCManager( 0, 0, SC_MANAGER_ALL_ACCESS
);
573 err
= translate_errno( scm
, (OSStatus
) GetLastError(), kOpenErr
);
574 require_noerr( err
, exit
);
576 service
= OpenService( scm
, inName
, SERVICE_STOP
| SERVICE_QUERY_STATUS
| DELETE
);
577 err
= translate_errno( service
, (OSStatus
) GetLastError(), kNotFoundErr
);
578 require_noerr( err
, exit
);
580 // Stop the service, if it is not already stopped, then delete it.
582 ok
= QueryServiceStatus( service
, &status
);
583 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kAuthenticationErr
);
584 require_noerr( err
, exit
);
586 if( status
.dwCurrentState
!= SERVICE_STOPPED
)
588 ok
= ControlService( service
, SERVICE_CONTROL_STOP
, &status
);
589 check_translated_errno( ok
, (OSStatus
) GetLastError(), kAuthenticationErr
);
592 ok
= DeleteService( service
);
593 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kDeletedErr
);
594 require_noerr( err
, exit
);
596 ReportStatus( EVENTLOG_SUCCESS
, "Removed service \"%s\"\n", inName
);
602 CloseServiceHandle( service
);
606 CloseServiceHandle( scm
);
613 //===========================================================================================================================
614 // SetServiceParameters
615 //===========================================================================================================================
617 static OSStatus
SetServiceParameters()
620 DWORD valueLen
= sizeof(DWORD
);
628 // Add/Open Parameters section under service entry in registry
630 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
, &key
);
631 require_noerr( err
, exit
);
634 // If the value isn't already there, then we create it
636 err
= RegQueryValueEx(key
, kServiceManageLLRouting
, 0, &type
, (LPBYTE
) &value
, &valueLen
);
638 if (err
!= ERROR_SUCCESS
)
642 err
= RegSetValueEx( key
, kServiceManageLLRouting
, 0, REG_DWORD
, (const LPBYTE
) &value
, sizeof(DWORD
) );
643 require_noerr( err
, exit
);
658 //===========================================================================================================================
659 // GetServiceParameters
660 //===========================================================================================================================
662 static OSStatus
GetServiceParameters()
673 // Add/Open Parameters section under service entry in registry
675 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
, &key
);
676 require_noerr( err
, exit
);
678 valueLen
= sizeof(DWORD
);
679 err
= RegQueryValueEx(key
, kServiceManageLLRouting
, 0, &type
, (LPBYTE
) &value
, &valueLen
);
680 if (err
== ERROR_SUCCESS
)
682 gServiceManageLLRouting
= (value
) ? true : false;
685 valueLen
= sizeof(DWORD
);
686 err
= RegQueryValueEx(key
, kServiceCacheEntryCount
, 0, &type
, (LPBYTE
) &value
, &valueLen
);
687 if (err
== ERROR_SUCCESS
)
689 gServiceCacheEntryCount
= value
;
703 //===========================================================================================================================
705 //===========================================================================================================================
707 static OSStatus
CheckFirewall()
712 ENUM_SERVICE_STATUS
* lpService
= NULL
;
716 DWORD bytesNeeded
= 0;
718 DWORD resumeHandle
= 0;
723 BOOL isRunning
= FALSE
;
724 OSStatus err
= kUnknownErr
;
726 // Check to see if the firewall service is running. If it isn't, then
727 // we want to return immediately
729 sc
= OpenSCManager( NULL
, NULL
, SC_MANAGER_ENUMERATE_SERVICE
);
730 err
= translate_errno( sc
, GetLastError(), kUnknownErr
);
731 require_noerr( err
, exit
);
733 srvType
= SERVICE_WIN32
;
734 srvState
= SERVICE_STATE_ALL
;
738 // Call EnumServicesStatus using the handle returned by OpenSCManager
740 ok
= EnumServicesStatus ( sc
, srvType
, srvState
, lpService
, dwBytes
, &bytesNeeded
, &srvCount
, &resumeHandle
);
742 if ( ok
|| ( GetLastError() != ERROR_MORE_DATA
) )
752 dwBytes
= bytesNeeded
;
754 lpService
= ( ENUM_SERVICE_STATUS
* ) malloc( dwBytes
);
755 require_action( lpService
, exit
, err
= mStatus_NoMemoryErr
);
758 err
= translate_errno( ok
, GetLastError(), kUnknownErr
);
759 require_noerr( err
, exit
);
761 for ( i
= 0; i
< srvCount
; i
++ )
763 if ( wcscmp( lpService
[i
].lpServiceName
, L
"SharedAccess" ) == 0 )
765 if ( lpService
[i
].ServiceStatus
.dwCurrentState
== SERVICE_RUNNING
)
774 require_action( isRunning
, exit
, err
= kUnknownErr
);
776 // Check to see if we've managed the firewall.
777 // This package might have been installed, then
778 // the OS was upgraded to SP2 or above. If that's
779 // the case, then we need to manipulate the firewall
780 // so networking works correctly.
782 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
, &key
);
783 require_noerr( err
, exit
);
785 valueLen
= sizeof(DWORD
);
786 err
= RegQueryValueEx(key
, kServiceManageFirewall
, 0, &type
, (LPBYTE
) &value
, &valueLen
);
788 if ((err
!= ERROR_SUCCESS
) || (value
== 0))
790 wchar_t fullPath
[ MAX_PATH
];
793 // Get a full path to the executable
795 size
= GetModuleFileNameW( NULL
, fullPath
, sizeof( fullPath
) );
796 err
= translate_errno( size
> 0, (OSStatus
) GetLastError(), kPathErr
);
797 require_noerr( err
, exit
);
799 err
= mDNSAddToFirewall(fullPath
, kServiceFirewallName
);
800 require_noerr( err
, exit
);
803 err
= RegSetValueEx( key
, kServiceManageFirewall
, 0, REG_DWORD
, (const LPBYTE
) &value
, sizeof( DWORD
) );
804 require_noerr( err
, exit
);
821 CloseServiceHandle ( sc
);
829 //===========================================================================================================================
831 //===========================================================================================================================
833 static OSStatus
SetServiceInfo( SC_HANDLE inSCM
, LPCTSTR inServiceName
, LPCTSTR inDescription
)
838 SERVICE_DESCRIPTION description
;
839 SERVICE_FAILURE_ACTIONS actions
;
843 check( inServiceName
);
844 check( inDescription
);
849 // Open the database (if not provided) and lock it to prevent other access while re-configuring.
853 inSCM
= OpenSCManager( NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
854 err
= translate_errno( inSCM
, (OSStatus
) GetLastError(), kOpenErr
);
855 require_noerr( err
, exit
);
858 lock
= LockServiceDatabase( inSCM
);
859 err
= translate_errno( lock
, (OSStatus
) GetLastError(), kInUseErr
);
860 require_noerr( err
, exit
);
862 // Open a handle to the service.
864 service
= OpenService( inSCM
, inServiceName
, SERVICE_CHANGE_CONFIG
|SERVICE_START
);
865 err
= translate_errno( service
, (OSStatus
) GetLastError(), kNotFoundErr
);
866 require_noerr( err
, exit
);
868 // Change the description.
870 description
.lpDescription
= (LPTSTR
) inDescription
;
871 ok
= ChangeServiceConfig2( service
, SERVICE_CONFIG_DESCRIPTION
, &description
);
872 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kParamErr
);
873 require_noerr( err
, exit
);
875 actions
.dwResetPeriod
= INFINITE
;
876 actions
.lpRebootMsg
= NULL
;
877 actions
.lpCommand
= NULL
;
878 actions
.cActions
= 1;
879 actions
.lpsaActions
= &action
;
881 action
.Type
= SC_ACTION_RESTART
;
883 ok
= ChangeServiceConfig2( service
, SERVICE_CONFIG_FAILURE_ACTIONS
, &actions
);
884 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kParamErr
);
885 require_noerr( err
, exit
);
890 // Close the service and release the lock.
894 CloseServiceHandle( service
);
898 UnlockServiceDatabase( lock
);
903 //===========================================================================================================================
905 //===========================================================================================================================
907 static void ReportStatus( int inType
, const char *inFormat
, ... )
909 if( !gServiceQuietMode
)
913 va_start( args
, inFormat
);
914 if( gServiceEventSource
)
918 const char * array
[ 1 ];
920 vsprintf( s
, inFormat
, args
);
922 ok
= ReportEventA( gServiceEventSource
, (WORD
) inType
, 0, 0x20000001L
, NULL
, 1, 0, array
, NULL
);
923 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
929 n
= vfprintf( stderr
, inFormat
, args
);
936 //===========================================================================================================================
938 //===========================================================================================================================
940 static OSStatus
RunDirect( int argc
, LPTSTR argv
[] )
948 // Install a Console Control Handler to handle things like control-c signals.
950 ok
= SetConsoleCtrlHandler( ConsoleControlHandler
, TRUE
);
951 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
952 require_noerr( err
, exit
);
954 err
= ServiceSpecificInitialize( argc
, argv
);
955 require_noerr( err
, exit
);
958 // Run the service. This does not return until the service quits or is stopped.
960 ReportStatus( EVENTLOG_SUCCESS
, "Running \"%s\" service directly\n", kServiceName
);
962 err
= ServiceSpecificRun( argc
, argv
);
963 require_noerr( err
, exit
);
970 ServiceSpecificFinalize( argc
, argv
);
979 //===========================================================================================================================
981 //===========================================================================================================================
983 static void WINAPI
ServiceMain( DWORD argc
, LPTSTR argv
[] )
988 err
= ServiceSetupEventLogging();
991 err
= GetServiceParameters();
994 // Initialize the service status and register the service control handler with the name of the service.
996 gServiceStatus
.dwServiceType
= SERVICE_WIN32_SHARE_PROCESS
;
997 gServiceStatus
.dwCurrentState
= 0;
998 gServiceStatus
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
|SERVICE_ACCEPT_POWEREVENT
;
999 gServiceStatus
.dwWin32ExitCode
= NO_ERROR
;
1000 gServiceStatus
.dwServiceSpecificExitCode
= NO_ERROR
;
1001 gServiceStatus
.dwCheckPoint
= 0;
1002 gServiceStatus
.dwWaitHint
= 0;
1004 gServiceStatusHandle
= RegisterServiceCtrlHandlerEx( argv
[ 0 ], ServiceControlHandler
, NULL
);
1005 err
= translate_errno( gServiceStatusHandle
, (OSStatus
) GetLastError(), kInUseErr
);
1006 require_noerr( err
, exit
);
1008 // Mark the service as starting.
1010 gServiceStatus
.dwCurrentState
= SERVICE_START_PENDING
;
1011 gServiceStatus
.dwCheckPoint
= 0;
1012 gServiceStatus
.dwWaitHint
= 5000; // 5 seconds
1013 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
1014 check_translated_errno( ok
, GetLastError(), kParamErr
);
1016 // Run the service. This does not return until the service quits or is stopped.
1018 err
= ServiceRun( (int) argc
, argv
);
1021 gServiceStatus
.dwWin32ExitCode
= ERROR_SERVICE_SPECIFIC_ERROR
;
1022 gServiceStatus
.dwServiceSpecificExitCode
= (DWORD
) err
;
1025 // Service-specific work is done so mark the service as stopped.
1027 gServiceStatus
.dwCurrentState
= SERVICE_STOPPED
;
1028 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
1029 check_translated_errno( ok
, GetLastError(), kParamErr
);
1031 // Note: The service status handle should not be closed according to Microsoft documentation.
1034 if( gServiceEventSource
)
1036 ok
= DeregisterEventSource( gServiceEventSource
);
1037 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
1038 gServiceEventSource
= NULL
;
1042 //===========================================================================================================================
1043 // ServiceSetupEventLogging
1044 //===========================================================================================================================
1046 static OSStatus
ServiceSetupEventLogging( void )
1051 DWORD typesSupported
;
1052 TCHAR path
[ MAX_PATH
];
1057 // Add/Open source name as a sub-key under the Application key in the EventLog registry key.
1059 s
= TEXT("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\") kServiceName
;
1060 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, s
, &key
);
1061 require_noerr( err
, exit
);
1063 // Add the name to the EventMessageFile subkey.
1066 GetModuleFileName( NULL
, path
, MAX_PATH
);
1067 n
= (DWORD
) ( ( StrLen( path
) + 1 ) * sizeof( TCHAR
) );
1068 err
= RegSetValueEx( key
, TEXT("EventMessageFile"), 0, REG_EXPAND_SZ
, (const LPBYTE
) path
, n
);
1069 require_noerr( err
, exit
);
1071 // Set the supported event types in the TypesSupported subkey.
1075 | EVENTLOG_ERROR_TYPE
1076 | EVENTLOG_WARNING_TYPE
1077 | EVENTLOG_INFORMATION_TYPE
1078 | EVENTLOG_AUDIT_SUCCESS
1079 | EVENTLOG_AUDIT_FAILURE
;
1080 err
= RegSetValueEx( key
, TEXT("TypesSupported"), 0, REG_DWORD
, (const LPBYTE
) &typesSupported
, sizeof( DWORD
) );
1081 require_noerr( err
, exit
);
1083 // Set up the event source.
1085 gServiceEventSource
= RegisterEventSource( NULL
, kServiceName
);
1086 err
= translate_errno( gServiceEventSource
, (OSStatus
) GetLastError(), kParamErr
);
1087 require_noerr( err
, exit
);
1097 //===========================================================================================================================
1098 // ServiceControlHandler
1099 //===========================================================================================================================
1101 static DWORD WINAPI
ServiceControlHandler( DWORD inControl
, DWORD inEventType
, LPVOID inEventData
, LPVOID inContext
)
1106 DEBUG_UNUSED( inEventData
);
1107 DEBUG_UNUSED( inContext
);
1112 case SERVICE_CONTROL_STOP
:
1113 dlog( kDebugLevelNotice
, DEBUG_NAME
"ServiceControlHandler: SERVICE_CONTROL_STOP\n" );
1119 case SERVICE_CONTROL_POWEREVENT
:
1121 if (inEventType
== PBT_APMSUSPEND
)
1123 mDNSCoreMachineSleep(&gMDNSRecord
, TRUE
);
1125 else if (inEventType
== PBT_APMRESUMESUSPEND
)
1127 mDNSCoreMachineSleep(&gMDNSRecord
, FALSE
);
1133 dlog( kDebugLevelNotice
, DEBUG_NAME
"ServiceControlHandler: event (0x%08X)\n", inControl
);
1137 if( setStatus
&& gServiceStatusHandle
)
1139 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
1140 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
1146 //===========================================================================================================================
1148 //===========================================================================================================================
1150 static OSStatus
ServiceRun( int argc
, LPTSTR argv
[] )
1156 DEBUG_UNUSED( argc
);
1157 DEBUG_UNUSED( argv
);
1159 initialized
= FALSE
;
1161 // Initialize the service-specific stuff and mark the service as running.
1163 err
= ServiceSpecificInitialize( argc
, argv
);
1164 require_noerr( err
, exit
);
1167 gServiceStatus
.dwCurrentState
= SERVICE_RUNNING
;
1168 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
1169 check_translated_errno( ok
, GetLastError(), kParamErr
);
1171 err
= CheckFirewall();
1176 gRetryFirewall
= TRUE
;
1179 // Run the service-specific stuff. This does not return until the service quits or is stopped.
1181 ReportStatus( EVENTLOG_INFORMATION_TYPE
, "mDNSResponder started\n" );
1182 err
= ServiceSpecificRun( argc
, argv
);
1183 ReportStatus( EVENTLOG_INFORMATION_TYPE
, "mDNSResponder stopped (%d)\n", err
);
1184 require_noerr( err
, exit
);
1186 // Service stopped. Clean up and we're done.
1191 ServiceSpecificFinalize( argc
, argv
);
1196 //===========================================================================================================================
1198 //===========================================================================================================================
1200 static void ServiceStop( void )
1205 // Signal the event to cause the service to exit.
1207 if( gServiceStatusHandle
)
1209 gServiceStatus
.dwCurrentState
= SERVICE_STOP_PENDING
;
1210 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
1211 check_translated_errno( ok
, GetLastError(), kParamErr
);
1214 err
= ServiceSpecificStop();
1220 #pragma mark == Service Specific ==
1223 //===========================================================================================================================
1224 // ServiceSpecificInitialize
1225 //===========================================================================================================================
1227 static OSStatus
ServiceSpecificInitialize( int argc
, LPTSTR argv
[] )
1231 DEBUG_UNUSED( argc
);
1232 DEBUG_UNUSED( argv
);
1234 memset( &gMDNSRecord
, 0, sizeof gMDNSRecord
);
1235 memset( &gPlatformStorage
, 0, sizeof gPlatformStorage
);
1237 gPlatformStorage
.idleThreadCallback
= udsIdle
;
1238 gPlatformStorage
.hostDescriptionChangedCallback
= HostDescriptionChanged
;
1240 InitializeCriticalSection(&gEventSourceLock
);
1242 gStopEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1243 err
= translate_errno( gStopEvent
, errno_compat(), kNoResourcesErr
);
1244 require_noerr( err
, exit
);
1246 err
= mDNS_Init( &gMDNSRecord
, &gPlatformStorage
, gRRCache
, RR_CACHE_SIZE
, mDNS_Init_AdvertiseLocalAddresses
, CoreCallback
, mDNS_Init_NoInitCallbackContext
);
1247 require_noerr( err
, exit
);
1249 err
= udsserver_init();
1250 require_noerr( err
, exit
);
1253 // <rdar://problem/4096464> Don't call SetLLRoute on loopback
1255 // Otherwise, set a route to link local addresses (169.254.0.0)
1258 if ( gServiceManageLLRouting
&& !gPlatformStorage
.registeredLoopback4
)
1260 SetLLRoute( &gMDNSRecord
);
1266 ServiceSpecificFinalize( argc
, argv
);
1271 //===========================================================================================================================
1272 // ServiceSpecificRun
1273 //===========================================================================================================================
1275 static OSStatus
ServiceSpecificRun( int argc
, LPTSTR argv
[] )
1280 DEBUG_UNUSED( argc
);
1281 DEBUG_UNUSED( argv
);
1283 // Main event loop. Process connection requests and state changes (i.e. quit).
1285 timeout
= ( gRetryFirewall
) ? kRetryFirewallPeriod
: INFINITE
;
1287 while( (result
= WaitForSingleObject( gStopEvent
, timeout
) ) != WAIT_OBJECT_0
)
1289 if ( result
== WAIT_TIMEOUT
)
1293 err
= CheckFirewall();
1300 // Unexpected wait result.
1301 dlog( kDebugLevelWarning
, DEBUG_NAME
"%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__
, result
);
1308 //===========================================================================================================================
1309 // ServiceSpecificStop
1310 //===========================================================================================================================
1312 static OSStatus
ServiceSpecificStop( void )
1317 ok
= SetEvent(gStopEvent
);
1318 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
1319 require_noerr( err
, exit
);
1324 //===========================================================================================================================
1325 // ServiceSpecificFinalize
1326 //===========================================================================================================================
1328 static void ServiceSpecificFinalize( int argc
, LPTSTR argv
[] )
1330 DEBUG_UNUSED( argc
);
1331 DEBUG_UNUSED( argv
);
1334 // clean up any open sessions
1336 while (gEventSources
.Head
)
1338 EventSourceFinalize((Win32EventSource
*) gEventSources
.Head
);
1341 // give a chance for the udsserver code to clean up
1346 // and finally close down the mDNSCore
1348 mDNS_Close(&gMDNSRecord
);
1351 // clean up the event sources mutex...no one should be using it now
1353 DeleteCriticalSection(&gEventSourceLock
);
1358 CoreCallback(mDNS
* const inMDNS
, mStatus status
)
1360 if (status
== mStatus_ConfigChanged
)
1363 // <rdar://problem/4096464> Don't call SetLLRoute on loopback
1365 // Otherwise, set a route to link local addresses (169.254.0.0)
1368 if ( gServiceManageLLRouting
&& !inMDNS
->p
->registeredLoopback4
)
1370 SetLLRoute( inMDNS
);
1377 udsIdle(mDNS
* const inMDNS
, mDNSs32 interval
)
1379 DEBUG_UNUSED( inMDNS
);
1382 // rdar://problem/3697326
1384 // udsserver_idle wasn't being locked. This resulted
1385 // in multiple threads contesting for the all_requests
1386 // data structure in uds_daemon.c
1388 mDNSPlatformLock(&gMDNSRecord
);
1390 interval
= udsserver_idle(interval
);
1392 mDNSPlatformUnlock(&gMDNSRecord
);
1399 HostDescriptionChanged(mDNS
* const inMDNS
)
1401 DEBUG_UNUSED( inMDNS
);
1403 udsserver_handle_configchange();
1407 mDNSlocal
unsigned WINAPI
1408 udsSocketThread(LPVOID inParam
)
1410 Win32EventSource
* source
= (Win32EventSource
*) inParam
;
1411 DWORD threadID
= GetCurrentThreadId();
1416 bool locked
= false;
1419 waitCount
= source
->waitCount
;
1420 waitList
[0] = source
->waitList
[0];
1421 waitList
[1] = source
->waitList
[1];
1422 done
= (bool) (source
->flags
& EventSourceFinalized
);
1428 result
= WaitForMultipleObjects(waitCount
, waitList
, FALSE
, INFINITE
);
1430 mDNSPlatformLock(&gMDNSRecord
);
1433 // <rdar://problem/3838237>
1435 // Look up the source by the thread id. This will ensure that the
1436 // source is still extant. It could already have been deleted
1437 // by the processing thread.
1442 for (source
= gEventSources
.Head
; source
; source
= source
->next
)
1444 if (source
->threadID
== threadID
)
1450 EventSourceUnlock();
1460 if (result
== WAIT_OBJECT_0
)
1462 source
->callback(source
->context
);
1467 else if (result
== WAIT_OBJECT_0
+ 1)
1470 // this is a bit of a hack. we want to clean up the internal data structures
1471 // so we'll go in here and it will clean up for us
1473 shutdown(source
->sock
, 2);
1474 source
->callback(source
->context
);
1480 // Unexpected wait result.
1481 dlog( kDebugLevelWarning
, DEBUG_NAME
"%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__
, result
);
1485 done
= (bool) (source
->flags
& EventSourceFinalized
);
1487 mDNSPlatformUnlock(&gMDNSRecord
);
1492 source
->flags
|= EventSourceFlagsThreadDone
;
1493 safeToClose
= !( source
->flags
& EventSourceFlagsNoClose
);
1494 EventSourceUnlock();
1498 EventSourceFinalize( source
);
1505 mDNSPlatformUnlock(&gMDNSRecord
);
1508 _endthreadex_compat( (unsigned) err
);
1509 return( (unsigned) err
);
1514 udsSupportAddFDToEventLoop( SocketRef fd
, udsEventCallback callback
, void *context
)
1516 Win32EventSource
* newSource
;
1520 newSource
= malloc(sizeof(Win32EventSource
));
1521 require_action( newSource
, exit
, err
= mStatus_NoMemoryErr
);
1522 memset(newSource
, 0, sizeof(Win32EventSource
));
1524 newSource
->flags
= 0;
1525 newSource
->sock
= (SOCKET
) fd
;
1526 newSource
->callback
= callback
;
1527 newSource
->context
= context
;
1529 newSource
->socketEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1530 err
= translate_errno( newSource
->socketEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1531 require_noerr( err
, exit
);
1533 newSource
->closeEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1534 err
= translate_errno( newSource
->closeEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1535 require_noerr( err
, exit
);
1537 err
= WSAEventSelect(newSource
->sock
, newSource
->socketEvent
, FD_ACCEPT
|FD_READ
|FD_CLOSE
);
1538 err
= translate_errno( err
== 0, errno_compat(), kNoResourcesErr
);
1539 require_noerr( err
, exit
);
1541 newSource
->waitCount
= 0;
1542 newSource
->waitList
[ newSource
->waitCount
++ ] = newSource
->socketEvent
;
1543 newSource
->waitList
[ newSource
->waitCount
++ ] = newSource
->closeEvent
;
1550 // add the event source to the end of the list, while checking
1551 // to see if the list needs to be initialized
1553 if ( gEventSources
.LinkOffset
== 0)
1555 InitLinkedList( &gEventSources
, offsetof( Win32EventSource
, next
));
1558 AddToTail( &gEventSources
, newSource
);
1561 // no longer using the list
1563 EventSourceUnlock();
1565 // Create thread with _beginthreadex() instead of CreateThread() to avoid memory leaks when using static run-time
1566 // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
1567 // Create the thread suspended then resume it so the thread handle and ID are valid before the thread starts running.
1568 newSource
->threadHandle
= (HANDLE
) _beginthreadex_compat( NULL
, 0, udsSocketThread
, newSource
, CREATE_SUSPENDED
, &newSource
->threadID
);
1569 err
= translate_errno( newSource
->threadHandle
, (mStatus
) GetLastError(), kUnknownErr
);
1570 require_noerr( err
, exit
);
1572 result
= ResumeThread( newSource
->threadHandle
);
1573 err
= translate_errno( result
!= (DWORD
) -1, errno_compat(), kNoResourcesErr
);
1574 require_noerr( err
, exit
);
1578 if (err
&& newSource
)
1580 EventSourceFinalize(newSource
);
1588 udsSupportRemoveFDFromEventLoop( SocketRef fd
) // Note: This also CLOSES the socket
1590 Win32EventSource
* source
;
1591 mStatus err
= mStatus_NoError
;
1594 // find the event source
1598 for (source
= gEventSources
.Head
; source
; source
= source
->next
)
1600 if (source
->sock
== (SOCKET
) fd
)
1607 // if we found him, finalize him
1611 EventSourceFinalize(source
);
1615 // done with the list
1617 EventSourceUnlock();
1625 mDNSexport
void RecordUpdatedNiceLabel(mDNS
*const m
, mDNSs32 delay
)
1634 EventSourceFinalize(Win32EventSource
* source
)
1638 Win32EventSource
* inserted
;
1647 // Find the session in the list.
1652 for( inserted
= (Win32EventSource
*) gEventSources
.Head
; inserted
; inserted
= inserted
->next
)
1654 if( inserted
== source
)
1659 require_action( inserted
, exit
, err
= kNotFoundErr
);
1662 // note that we've had finalize called
1664 source
->flags
|= EventSourceFinalized
;
1666 // If we're being called from the same thread as the session (e.g. message callback is closing the session) then
1667 // we must defer the close until the thread is done because the thread is still using the session object.
1670 threadID
= GetCurrentThreadId();
1671 sameThread
= source
->threadHandle
&& ( threadID
== source
->threadID
);
1672 if( sameThread
&& !( source
->flags
& EventSourceFlagsThreadDone
) )
1674 source
->flags
&= ~EventSourceFlagsNoClose
;
1678 // If the thread we're not being called from the session thread, but the thread has already marked itself as
1679 // as done (e.g. session closed from something like a peer disconnect and at the same time the client also
1680 // tried to close) then we only want to continue with the close if the thread is not going to close itself.
1682 if( !sameThread
&& ( source
->flags
& EventSourceFlagsThreadDone
) && !( source
->flags
& EventSourceFlagsNoClose
) )
1687 // Signal a close so the thread exits.
1689 if( source
->closeEvent
)
1691 ok
= SetEvent( source
->closeEvent
);
1692 check_translated_errno( ok
, errno_compat(), kUnknownErr
);
1700 source
->flags
|= EventSourceFlagsNoClose
;
1702 // Remove the session from the list.
1703 RemoveFromList(&gEventSources
, source
);
1705 EventSourceUnlock();
1708 // Wait for the thread to exit. Give up after 3 seconds to handle a hung thread.
1710 if( source
->threadHandle
&& ( threadID
!= source
->threadID
) )
1712 result
= WaitForSingleObject( source
->threadHandle
, 3 * 1000 );
1713 check_translated_errno( result
== WAIT_OBJECT_0
, (OSStatus
) GetLastError(), result
);
1716 // Release the thread.
1718 if( source
->threadHandle
)
1720 ok
= CloseHandle( source
->threadHandle
);
1721 check_translated_errno( ok
, errno_compat(), kUnknownErr
);
1722 source
->threadHandle
= NULL
;
1725 // Release the socket event.
1727 if( source
->socketEvent
)
1729 ok
= CloseHandle( source
->socketEvent
);
1730 check_translated_errno( ok
, errno_compat(), kUnknownErr
);
1731 source
->socketEvent
= NULL
;
1734 // Release the close event.
1736 if( source
->closeEvent
)
1738 ok
= CloseHandle( source
->closeEvent
);
1739 check_translated_errno( ok
, errno_compat(), kUnknownErr
);
1740 source
->closeEvent
= NULL
;
1743 // Release the memory used by the object.
1748 dlog( kDebugLevelNotice
, DEBUG_NAME
"session closed\n" );
1754 EventSourceUnlock();
1764 EnterCriticalSection(&gEventSourceLock
);
1771 LeaveCriticalSection(&gEventSourceLock
);
1775 //===========================================================================================================================
1777 //===========================================================================================================================
1780 HaveRoute( PMIB_IPFORWARDROW rowExtant
, unsigned long addr
)
1782 PMIB_IPFORWARDTABLE pIpForwardTable
= NULL
;
1784 BOOL bOrder
= FALSE
;
1787 unsigned long int i
;
1790 // Find out how big our buffer needs to be.
1792 err
= GetIpForwardTable(NULL
, &dwSize
, bOrder
);
1793 require_action( err
== ERROR_INSUFFICIENT_BUFFER
, exit
, err
= kUnknownErr
);
1796 // Allocate the memory for the table
1798 pIpForwardTable
= (PMIB_IPFORWARDTABLE
) malloc( dwSize
);
1799 require_action( pIpForwardTable
, exit
, err
= kNoMemoryErr
);
1802 // Now get the table.
1804 err
= GetIpForwardTable(pIpForwardTable
, &dwSize
, bOrder
);
1805 require_noerr( err
, exit
);
1808 // Search for the row in the table we want.
1810 for ( i
= 0; i
< pIpForwardTable
->dwNumEntries
; i
++)
1812 if ( pIpForwardTable
->table
[i
].dwForwardDest
== addr
)
1814 memcpy( rowExtant
, &(pIpForwardTable
->table
[i
]), sizeof(*rowExtant
) );
1822 if ( pIpForwardTable
!= NULL
)
1824 free(pIpForwardTable
);
1831 //===========================================================================================================================
1833 //===========================================================================================================================
1836 IsValidAddress( const char * addr
)
1838 return ( addr
&& ( strcmp( addr
, "0.0.0.0" ) != 0 ) ) ? true : false;
1842 //===========================================================================================================================
1844 //===========================================================================================================================
1847 SetLLRoute( mDNS
* const inMDNS
)
1850 MIB_IPFORWARDROW rowExtant
;
1852 MIB_IPFORWARDROW row
;
1855 ZeroMemory(&row
, sizeof(row
));
1857 err
= GetRouteDestination(&ifIndex
, &row
.dwForwardNextHop
);
1858 require_noerr( err
, exit
);
1859 row
.dwForwardDest
= inet_addr(kLLNetworkAddr
);
1860 row
.dwForwardIfIndex
= ifIndex
;
1861 row
.dwForwardMask
= inet_addr(kLLNetworkAddrMask
);
1862 row
.dwForwardType
= 3;
1863 row
.dwForwardProto
= MIB_IPPROTO_NETMGMT
;
1864 row
.dwForwardAge
= 0;
1865 row
.dwForwardPolicy
= 0;
1866 row
.dwForwardMetric1
= 30;
1867 row
.dwForwardMetric2
= (DWORD
) - 1;
1868 row
.dwForwardMetric3
= (DWORD
) - 1;
1869 row
.dwForwardMetric4
= (DWORD
) - 1;
1870 row
.dwForwardMetric5
= (DWORD
) - 1;
1875 // check to make sure we don't already have a route
1877 if ( HaveRoute( &rowExtant
, inet_addr( kLLNetworkAddr
) ) )
1880 // set the age to 0 so that we can do a memcmp.
1882 rowExtant
.dwForwardAge
= 0;
1885 // check to see if this route is the same as our route
1887 if (memcmp(&row
, &rowExtant
, sizeof(row
)) != 0)
1890 // if it isn't then delete this entry
1892 DeleteIpForwardEntry(&rowExtant
);
1897 // else it is, so we don't want to create another route
1903 if (addRoute
&& row
.dwForwardNextHop
)
1905 err
= CreateIpForwardEntry(&row
);
1907 require_noerr( err
, exit
);
1911 // Now we want to see if we should install a default route for this interface.
1912 // We want to do this if the following are true:
1914 // 1. This interface has a link-local address
1915 // 2. This is the only IPv4 interface
1918 if ( ( row
.dwForwardNextHop
& 0xFFFF ) == row
.dwForwardDest
)
1920 mDNSInterfaceData
* ifd
;
1921 int numLinkLocalInterfaces
= 0;
1922 int numInterfaces
= 0;
1924 for ( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
1926 if ( ifd
->defaultAddr
.type
== mDNSAddrType_IPv4
)
1930 if ( ( ifd
->interfaceInfo
.ip
.ip
.v4
.b
[0] == 169 ) && ( ifd
->interfaceInfo
.ip
.ip
.v4
.b
[1] == 254 ) )
1932 numLinkLocalInterfaces
++;
1937 row
.dwForwardDest
= 0;
1938 row
.dwForwardIfIndex
= ifIndex
;
1939 row
.dwForwardMask
= 0;
1940 row
.dwForwardType
= 3;
1941 row
.dwForwardProto
= MIB_IPPROTO_NETMGMT
;
1942 row
.dwForwardAge
= 0;
1943 row
.dwForwardPolicy
= 0;
1944 row
.dwForwardMetric1
= 20;
1945 row
.dwForwardMetric2
= (DWORD
) - 1;
1946 row
.dwForwardMetric3
= (DWORD
) - 1;
1947 row
.dwForwardMetric4
= (DWORD
) - 1;
1948 row
.dwForwardMetric5
= (DWORD
) - 1;
1950 if ( numInterfaces
== numLinkLocalInterfaces
)
1952 if ( !HaveRoute( &row
, 0 ) )
1954 err
= CreateIpForwardEntry(&row
);
1955 require_noerr( err
, exit
);
1960 DeleteIpForwardEntry( &row
);
1970 //===========================================================================================================================
1971 // GetRouteDestination
1972 //===========================================================================================================================
1975 GetRouteDestination(DWORD
* ifIndex
, DWORD
* address
)
1978 IP_ADAPTER_INFO
* pAdapterInfo
= NULL
;
1979 IP_ADAPTER_INFO
* pAdapter
= NULL
;
1981 mDNSBool done
= mDNSfalse
;
1985 // GetBestInterface will fail if there is no default gateway
1986 // configured. If that happens, we will just take the first
1987 // interface in the list. MSDN support says there is no surefire
1988 // way to manually determine what the best interface might
1989 // be for a particular network address.
1991 ia
.s_addr
= inet_addr(kLLNetworkAddr
);
1992 err
= GetBestInterface(*(IPAddr
*) &ia
, ifIndex
);
2000 // Make an initial call to GetAdaptersInfo to get
2001 // the necessary size into the bufLen variable
2003 err
= GetAdaptersInfo( NULL
, &bufLen
);
2004 require_action( err
== ERROR_BUFFER_OVERFLOW
, exit
, err
= kUnknownErr
);
2006 pAdapterInfo
= (IP_ADAPTER_INFO
*) malloc( bufLen
);
2007 require_action( pAdapterInfo
, exit
, err
= kNoMemoryErr
);
2009 err
= GetAdaptersInfo( pAdapterInfo
, &bufLen
);
2010 require_noerr( err
, exit
);
2012 pAdapter
= pAdapterInfo
;
2015 // <rdar://problem/3718122>
2017 // Look for the Nortel VPN virtual interface. This interface
2018 // is identified by it's unique MAC address: 44-45-53-54-42-00
2020 // If the interface is active (i.e., has a non-zero IP Address),
2021 // then we want to disable routing table modifications.
2025 if ((pAdapter
->Type
== MIB_IF_TYPE_ETHERNET
) &&
2026 (pAdapter
->AddressLength
== 6) &&
2027 (pAdapter
->Address
[0] == 0x44) &&
2028 (pAdapter
->Address
[1] == 0x45) &&
2029 (pAdapter
->Address
[2] == 0x53) &&
2030 (pAdapter
->Address
[3] == 0x54) &&
2031 (pAdapter
->Address
[4] == 0x42) &&
2032 (pAdapter
->Address
[5] == 0x00) &&
2033 (inet_addr( pAdapter
->IpAddressList
.IpAddress
.String
) != 0))
2038 pAdapter
= pAdapter
->Next
;
2043 pAdapter
= pAdapterInfo
;
2048 // If we don't have an interface selected, choose the first one that is of type ethernet and
2049 // has a valid IP Address
2051 if ((pAdapter
->Type
== MIB_IF_TYPE_ETHERNET
) && ( IsValidAddress( pAdapter
->IpAddressList
.IpAddress
.String
) ) && (!(*ifIndex
) || (pAdapter
->Index
== (*ifIndex
))))
2053 *address
= inet_addr( pAdapter
->IpAddressList
.IpAddress
.String
);
2054 *ifIndex
= pAdapter
->Index
;
2059 pAdapter
= pAdapter
->Next
;
2062 // If we found the right interface, or we weren't trying to find a specific interface then we're done
2064 if ( !err
|| !( *ifIndex
) )
2069 // Otherwise, try again by wildcarding the interface
2079 if ( pAdapterInfo
!= NULL
)
2081 free( pAdapterInfo
);