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.39 2006/08/14 23:26:07 cheshire
21 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
23 Revision 1.38 2005/10/05 20:55:15 herscher
24 <rdar://problem/4096464> Don't call SetLLRoute on loopback interface
26 Revision 1.37 2005/10/05 18:05:28 herscher
27 <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.
29 Revision 1.36 2005/09/11 22:12:42 herscher
30 <rdar://problem/4247793> Remove dependency on WMI. Ensure that the Windows firewall is turned on before trying to configure it.
32 Revision 1.35 2005/06/30 18:29:49 shersche
33 <rdar://problem/4090059> Don't overwrite the localized service description text
35 Revision 1.34 2005/04/22 07:34:23 shersche
36 Check an interface's address and make sure it's valid before using it to set link-local routes.
38 Revision 1.33 2005/04/13 17:48:23 shersche
39 <rdar://problem/4079667> Make sure there is only one default route for link-local addresses.
41 Revision 1.32 2005/04/06 01:32:05 shersche
42 Remove default route for link-local addressing when another interface comes up with a routable IPv4 address
44 Revision 1.31 2005/04/06 01:00:11 shersche
45 <rdar://problem/4080127> GetFullPathName() should be passed the number of TCHARs in the path buffer, not the size in bytes of the path buffer.
47 Revision 1.30 2005/04/06 00:52:43 shersche
48 <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.
50 Revision 1.29 2005/03/06 05:21:56 shersche
51 <rdar://problem/4037635> Fix corrupt UTF-8 name when non-ASCII system name used, enabled unicode support
53 Revision 1.28 2005/03/03 02:27:24 shersche
54 Include the RegNames.h header file for names of registry keys
56 Revision 1.27 2005/03/02 20:12:59 shersche
59 Revision 1.26 2005/02/15 08:00:27 shersche
60 <rdar://problem/4007151> Update name
62 Revision 1.25 2005/02/10 22:35:36 cheshire
63 <rdar://problem/3727944> Update name
65 Revision 1.24 2005/01/27 20:02:43 cheshire
66 udsSupportRemoveFDFromEventLoop() needs to close the SocketRef as well
68 Revision 1.23 2005/01/25 08:14:15 shersche
69 Change CacheRecord to CacheEntity
71 Revision 1.22 2004/12/10 13:18:40 cheshire
72 Create no-op function RecordUpdatedNiceLabel(), required by uds_daemon.c
74 Revision 1.21 2004/11/10 04:03:41 shersche
75 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.
77 Revision 1.20 2004/10/14 21:44:05 shersche
78 <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.
81 Revision 1.19 2004/10/12 17:59:55 shersche
82 <rdar://problem/3718122> Disable routing table modifications when Nortel VPN adapter is active
85 Revision 1.18 2004/10/11 21:57:50 shersche
86 <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.
89 Revision 1.17 2004/09/17 01:08:58 cheshire
90 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
91 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
92 declared in that file are ONLY appropriate to single-address-space embedded applications.
93 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
95 Revision 1.16 2004/09/16 18:49:34 shersche
96 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.
98 Revision 1.15 2004/09/15 17:13:33 shersche
101 Revision 1.14 2004/09/15 09:37:25 shersche
102 Add SharedAccess to dependency list, call CheckFirewall after sending status back to SCM
104 Revision 1.13 2004/09/13 07:35:10 shersche
105 <rdar://problem/3762235> Add mDNSResponder to Windows Firewall application list if SP2 is detected and app hasn't been added before
108 Revision 1.12 2004/09/11 21:18:32 shersche
109 <rdar://problem/3779502> Add route to ARP everything when a 169.254.x.x address is selected
112 Revision 1.11 2004/09/11 05:39:19 shersche
113 <rdar://problem/3780203> Detect power managment state changes, calling mDNSCoreMachineSleep(m, true) on sleep, and mDNSCoreMachineSleep(m, false) on resume
116 Revision 1.10 2004/08/16 21:45:24 shersche
117 Use the full pathname of executable when calling CreateService()
118 Submitted by: prepin@zetron.com
120 Revision 1.9 2004/08/11 01:59:41 cheshire
121 Remove "mDNS *globalInstance" parameter from udsserver_init()
123 Revision 1.8 2004/08/05 05:40:05 shersche
124 <rdar://problem/3751566> Only invoke SetConsoleCtrlHandler when running directly from command line.
125 <rdar://problem/3751481> Invoke udsserver_handle_configchange() when the computer description changes
126 Bug #: 3751481, 3751566
128 Revision 1.7 2004/07/26 05:35:07 shersche
129 ignore non-enet interfaces when setting up link-local routing
131 Revision 1.6 2004/07/20 06:48:26 shersche
132 <rdar://problem/3718122> Allow registry entries to dictate whether to manage link local routing
135 Revision 1.5 2004/07/09 19:08:07 shersche
136 <rdar://problem/3713762> ServiceSetupEventLogging() errors are handled gracefully
139 Revision 1.4 2004/06/24 20:58:15 shersche
140 Fix compiler error in Release build
141 Submitted by: herscher
143 Revision 1.3 2004/06/24 15:28:53 shersche
144 Automatically setup routes to link-local addresses upon interface list change events.
145 Submitted by: herscher
147 Revision 1.2 2004/06/23 16:56:00 shersche
148 <rdar://problem/3697326> locked call to udsserver_idle().
150 Submitted by: herscher
152 Revision 1.1 2004/06/18 04:16:41 rpantos
155 Revision 1.1 2004/01/30 02:58:39 bradley
156 mDNSResponder Windows Service. Provides global Bonjour support with an IPC interface.
164 #include "CommonServices.h"
165 #include "DebugServices.h"
166 #include "RegNames.h"
168 #include "uds_daemon.h"
169 #include "GenLinkedList.h"
171 #include "Resource.h"
173 #include "mDNSEmbeddedAPI.h"
174 #include "mDNSWin32.h"
176 #include "Firewall.h"
178 #if( !TARGET_OS_WINDOWS_CE )
181 #include <ipExport.h>
182 #include <iphlpapi.h>
187 #pragma mark == Constants ==
190 //===========================================================================================================================
192 //===========================================================================================================================
194 #define DEBUG_NAME "[Server] "
195 #define kServiceFirewallName L"Bonjour"
196 #define kServiceDependencies TEXT("Tcpip\0\0")
197 #define kDNSServiceCacheEntryCountDefault 512
198 #define kRetryFirewallPeriod 30 * 1000
200 #define RR_CACHE_SIZE 500
201 static CacheEntity gRRCache
[RR_CACHE_SIZE
];
203 #pragma mark == Structures ==
206 //===========================================================================================================================
208 //===========================================================================================================================
209 //---------------------------------------------------------------------------------------------------------------------------
210 /*! @typedef EventSourceFlags
212 @abstract Session flags.
214 @constant EventSourceFlagsNone No flags.
215 @constant EventSourceFlagsThreadDone Thread is no longer active.
216 @constant EventSourceFlagsNoClose Do not close the session when the thread exits.
217 @constant EventSourceFinalized Finalize has been called for this session
220 typedef uint32_t EventSourceFlags
;
222 #define EventSourceFlagsNone 0
223 #define EventSourceFlagsThreadDone ( 1 << 2 )
224 #define EventSourceFlagsNoClose ( 1 << 3 )
225 #define EventSourceFinalized ( 1 << 4 )
228 typedef struct Win32EventSource
230 EventSourceFlags flags
;
235 udsEventCallback callback
;
240 struct Win32EventSource
* next
;
245 #pragma mark == Prototypes ==
248 //===========================================================================================================================
250 //===========================================================================================================================
252 int __cdecl
wmain( int argc
, LPTSTR argv
[] );
254 int __cdecl
main( int argc
, char *argv
[] );
256 static void Usage( void );
257 static BOOL WINAPI
ConsoleControlHandler( DWORD inControlEvent
);
258 static OSStatus
InstallService( LPCTSTR inName
, LPCTSTR inDisplayName
, LPCTSTR inDescription
, LPCTSTR inPath
);
259 static OSStatus
RemoveService( LPCTSTR inName
);
260 static OSStatus
SetServiceParameters();
261 static OSStatus
GetServiceParameters();
262 static OSStatus
CheckFirewall();
263 static OSStatus
SetServiceInfo( SC_HANDLE inSCM
, LPCTSTR inServiceName
, LPCTSTR inDescription
);
264 static void ReportStatus( int inType
, const char *inFormat
, ... );
265 static OSStatus
RunDirect( int argc
, LPTSTR argv
[] );
267 static void WINAPI
ServiceMain( DWORD argc
, LPTSTR argv
[] );
268 static OSStatus
ServiceSetupEventLogging( void );
269 static DWORD WINAPI
ServiceControlHandler( DWORD inControl
, DWORD inEventType
, LPVOID inEventData
, LPVOID inContext
);
271 static OSStatus
ServiceRun( int argc
, LPTSTR argv
[] );
272 static void ServiceStop( void );
274 static OSStatus
ServiceSpecificInitialize( int argc
, LPTSTR argv
[] );
275 static OSStatus
ServiceSpecificRun( int argc
, LPTSTR argv
[] );
276 static OSStatus
ServiceSpecificStop( void );
277 static void ServiceSpecificFinalize( int argc
, LPTSTR argv
[] );
278 static mStatus
EventSourceFinalize(Win32EventSource
* source
);
279 static void EventSourceLock();
280 static void EventSourceUnlock();
281 static mDNSs32
udsIdle(mDNS
* const inMDNS
, mDNSs32 interval
);
282 static void CoreCallback(mDNS
* const inMDNS
, mStatus result
);
283 static void HostDescriptionChanged(mDNS
* const inMDNS
);
284 static OSStatus
GetRouteDestination(DWORD
* ifIndex
, DWORD
* address
);
285 static OSStatus
SetLLRoute( mDNS
* const inMDNS
);
286 static bool HaveRoute( PMIB_IPFORWARDROW rowExtant
, unsigned long addr
);
287 static bool IsValidAddress( const char * addr
);
290 # define StrLen(X) wcslen(X)
291 # define StrCmp(X,Y) wcscmp(X,Y)
293 # define StrLen(X) strlen(X)
294 # define StrCmp(X,Y) strcmp(X,Y)
298 #define kLLNetworkAddr "169.254.0.0"
299 #define kLLNetworkAddrMask "255.255.0.0"
302 #include "mDNSEmbeddedAPI.h"
305 #pragma mark == Globals ==
308 //===========================================================================================================================
310 //===========================================================================================================================
311 #define gMDNSRecord mDNSStorage
312 DEBUG_LOCAL mDNS_PlatformSupport gPlatformStorage
;
313 DEBUG_LOCAL BOOL gServiceQuietMode
= FALSE
;
314 DEBUG_LOCAL SERVICE_TABLE_ENTRY gServiceDispatchTable
[] =
316 { kServiceName
, ServiceMain
},
319 DEBUG_LOCAL SERVICE_STATUS gServiceStatus
;
320 DEBUG_LOCAL SERVICE_STATUS_HANDLE gServiceStatusHandle
= NULL
;
321 DEBUG_LOCAL HANDLE gServiceEventSource
= NULL
;
322 DEBUG_LOCAL
bool gServiceAllowRemote
= false;
323 DEBUG_LOCAL
int gServiceCacheEntryCount
= 0; // 0 means to use the DNS-SD default.
324 DEBUG_LOCAL
bool gServiceManageLLRouting
= true;
325 DEBUG_LOCAL
int gWaitCount
= 0;
326 DEBUG_LOCAL HANDLE
* gWaitList
= NULL
;
327 DEBUG_LOCAL HANDLE gStopEvent
= NULL
;
328 DEBUG_LOCAL CRITICAL_SECTION gEventSourceLock
;
329 DEBUG_LOCAL GenLinkedList gEventSources
;
330 DEBUG_LOCAL BOOL gRetryFirewall
= FALSE
;
337 //===========================================================================================================================
339 //===========================================================================================================================
341 int __cdecl
wmain( int argc
, wchar_t * argv
[] )
343 int __cdecl
main( int argc
, char *argv
[] )
351 debug_initialize( kDebugOutputTypeMetaConsole
);
352 debug_set_property( kDebugPropertyTagPrintLevel
, kDebugLevelVerbose
);
354 // Default to automatically starting the service dispatcher if no extra arguments are specified.
356 start
= ( argc
<= 1 );
360 for( i
= 1; i
< argc
; ++i
)
362 if( StrCmp( argv
[ i
], TEXT("-install") ) == 0 ) // Install
367 LoadString( GetModuleHandle( NULL
), IDS_SERVICE_DESCRIPTION
, desc
, sizeof( desc
) );
368 err
= InstallService( kServiceName
, kServiceName
, desc
, argv
[0] );
371 ReportStatus( EVENTLOG_ERROR_TYPE
, "install service failed (%d)\n", err
);
375 else if( StrCmp( argv
[ i
], TEXT("-remove") ) == 0 ) // Remove
377 err
= RemoveService( kServiceName
);
380 ReportStatus( EVENTLOG_ERROR_TYPE
, "remove service failed (%d)\n", err
);
384 else if( StrCmp( argv
[ i
], TEXT("-start") ) == 0 ) // Start
388 else if( StrCmp( argv
[ i
], TEXT("-server") ) == 0 ) // Server
390 err
= RunDirect( argc
, argv
);
393 ReportStatus( EVENTLOG_ERROR_TYPE
, "run service directly failed (%d)\n", err
);
397 else if( StrCmp( argv
[ i
], TEXT("-q") ) == 0 ) // Quiet Mode (toggle)
399 gServiceQuietMode
= !gServiceQuietMode
;
401 else if( ( StrCmp( argv
[ i
], TEXT("-help") ) == 0 ) || // Help
402 ( StrCmp( argv
[ i
], TEXT("-h") ) == 0 ) )
416 // Start the service dispatcher if requested. This does not return until all services have terminated. If any
417 // global initialization is needed, it should be done before starting the service dispatcher, but only if it
418 // will take less than 30 seconds. Otherwise, use a separate thread for it and start the dispatcher immediately.
422 ok
= StartServiceCtrlDispatcher( gServiceDispatchTable
);
423 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kInUseErr
);
426 ReportStatus( EVENTLOG_ERROR_TYPE
, "start service dispatcher failed (%d)\n", err
);
433 dlog( kDebugLevelTrace
, DEBUG_NAME
"exited (%d %m)\n", err
, err
);
437 //===========================================================================================================================
439 //===========================================================================================================================
441 static void Usage( void )
443 fprintf( stderr
, "\n" );
444 fprintf( stderr
, "mDNSResponder 1.0d1\n" );
445 fprintf( stderr
, "\n" );
446 fprintf( stderr
, " <no args> Runs the service normally\n" );
447 fprintf( stderr
, " -install Creates the service and starts it\n" );
448 fprintf( stderr
, " -remove Stops the service and deletes it\n" );
449 fprintf( stderr
, " -start Starts the service dispatcher after processing all other arguments\n" );
450 fprintf( stderr
, " -server Runs the service directly as a server (for debugging)\n" );
451 fprintf( stderr
, " -q Toggles Quiet Mode (no events or output)\n" );
452 fprintf( stderr
, " -remote Allow remote connections\n" );
453 fprintf( stderr
, " -cache n Number of mDNS cache entries (defaults to %d)\n", kDNSServiceCacheEntryCountDefault
);
454 fprintf( stderr
, " -h[elp] Display Help/Usage\n" );
455 fprintf( stderr
, "\n" );
458 //===========================================================================================================================
459 // ConsoleControlHandler
460 //===========================================================================================================================
462 static BOOL WINAPI
ConsoleControlHandler( DWORD inControlEvent
)
468 switch( inControlEvent
)
471 case CTRL_BREAK_EVENT
:
472 case CTRL_CLOSE_EVENT
:
473 case CTRL_LOGOFF_EVENT
:
474 case CTRL_SHUTDOWN_EVENT
:
475 err
= ServiceSpecificStop();
476 require_noerr( err
, exit
);
489 //===========================================================================================================================
491 //===========================================================================================================================
493 static OSStatus
InstallService( LPCTSTR inName
, LPCTSTR inDisplayName
, LPCTSTR inDescription
, LPCTSTR inPath
)
499 TCHAR fullPath
[ MAX_PATH
];
506 // Get a full path to the executable since a relative path may have been specified.
508 size
= GetFullPathName( inPath
, MAX_PATH
, fullPath
, &namePtr
);
509 err
= translate_errno( size
> 0, (OSStatus
) GetLastError(), kPathErr
);
510 require_noerr( err
, exit
);
512 // Create the service and start it.
514 scm
= OpenSCManager( NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
515 err
= translate_errno( scm
, (OSStatus
) GetLastError(), kOpenErr
);
516 require_noerr( err
, exit
);
518 service
= CreateService( scm
, inName
, inDisplayName
, SERVICE_ALL_ACCESS
, SERVICE_WIN32_SHARE_PROCESS
,
519 SERVICE_AUTO_START
, SERVICE_ERROR_NORMAL
, fullPath
, NULL
, NULL
, kServiceDependencies
,
521 err
= translate_errno( service
, (OSStatus
) GetLastError(), kDuplicateErr
);
522 require_noerr( err
, exit
);
524 err
= SetServiceParameters();
529 err
= SetServiceInfo( scm
, inName
, inDescription
);
533 ok
= StartService( service
, 0, NULL
);
534 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kInUseErr
);
535 require_noerr( err
, exit
);
537 ReportStatus( EVENTLOG_SUCCESS
, "installed service \"%s\"/\"%s\" at \"%s\"\n", inName
, inDisplayName
, inPath
);
543 CloseServiceHandle( service
);
547 CloseServiceHandle( scm
);
552 //===========================================================================================================================
554 //===========================================================================================================================
556 static OSStatus
RemoveService( LPCTSTR inName
)
562 SERVICE_STATUS status
;
567 // Open a connection to the service.
569 scm
= OpenSCManager( 0, 0, SC_MANAGER_ALL_ACCESS
);
570 err
= translate_errno( scm
, (OSStatus
) GetLastError(), kOpenErr
);
571 require_noerr( err
, exit
);
573 service
= OpenService( scm
, inName
, SERVICE_STOP
| SERVICE_QUERY_STATUS
| DELETE
);
574 err
= translate_errno( service
, (OSStatus
) GetLastError(), kNotFoundErr
);
575 require_noerr( err
, exit
);
577 // Stop the service, if it is not already stopped, then delete it.
579 ok
= QueryServiceStatus( service
, &status
);
580 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kAuthenticationErr
);
581 require_noerr( err
, exit
);
583 if( status
.dwCurrentState
!= SERVICE_STOPPED
)
585 ok
= ControlService( service
, SERVICE_CONTROL_STOP
, &status
);
586 check_translated_errno( ok
, (OSStatus
) GetLastError(), kAuthenticationErr
);
589 ok
= DeleteService( service
);
590 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kDeletedErr
);
591 require_noerr( err
, exit
);
593 ReportStatus( EVENTLOG_SUCCESS
, "Removed service \"%s\"\n", inName
);
599 CloseServiceHandle( service
);
603 CloseServiceHandle( scm
);
610 //===========================================================================================================================
611 // SetServiceParameters
612 //===========================================================================================================================
614 static OSStatus
SetServiceParameters()
617 DWORD valueLen
= sizeof(DWORD
);
625 // Add/Open Parameters section under service entry in registry
627 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
, &key
);
628 require_noerr( err
, exit
);
631 // If the value isn't already there, then we create it
633 err
= RegQueryValueEx(key
, kServiceManageLLRouting
, 0, &type
, (LPBYTE
) &value
, &valueLen
);
635 if (err
!= ERROR_SUCCESS
)
639 err
= RegSetValueEx( key
, kServiceManageLLRouting
, 0, REG_DWORD
, (const LPBYTE
) &value
, sizeof(DWORD
) );
640 require_noerr( err
, exit
);
655 //===========================================================================================================================
656 // GetServiceParameters
657 //===========================================================================================================================
659 static OSStatus
GetServiceParameters()
670 // Add/Open Parameters section under service entry in registry
672 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
, &key
);
673 require_noerr( err
, exit
);
675 valueLen
= sizeof(DWORD
);
676 err
= RegQueryValueEx(key
, kServiceManageLLRouting
, 0, &type
, (LPBYTE
) &value
, &valueLen
);
677 if (err
== ERROR_SUCCESS
)
679 gServiceManageLLRouting
= (value
) ? true : false;
682 valueLen
= sizeof(DWORD
);
683 err
= RegQueryValueEx(key
, kServiceCacheEntryCount
, 0, &type
, (LPBYTE
) &value
, &valueLen
);
684 if (err
== ERROR_SUCCESS
)
686 gServiceCacheEntryCount
= value
;
700 //===========================================================================================================================
702 //===========================================================================================================================
704 static OSStatus
CheckFirewall()
709 ENUM_SERVICE_STATUS
* lpService
= NULL
;
713 DWORD bytesNeeded
= 0;
715 DWORD resumeHandle
= 0;
720 BOOL isRunning
= FALSE
;
721 OSStatus err
= kUnknownErr
;
723 // Check to see if the firewall service is running. If it isn't, then
724 // we want to return immediately
726 sc
= OpenSCManager( NULL
, NULL
, SC_MANAGER_ENUMERATE_SERVICE
);
727 err
= translate_errno( sc
, GetLastError(), kUnknownErr
);
728 require_noerr( err
, exit
);
730 srvType
= SERVICE_WIN32
;
731 srvState
= SERVICE_STATE_ALL
;
735 // Call EnumServicesStatus using the handle returned by OpenSCManager
737 ok
= EnumServicesStatus ( sc
, srvType
, srvState
, lpService
, dwBytes
, &bytesNeeded
, &srvCount
, &resumeHandle
);
739 if ( ok
|| ( GetLastError() != ERROR_MORE_DATA
) )
749 dwBytes
= bytesNeeded
;
751 lpService
= ( ENUM_SERVICE_STATUS
* ) malloc( dwBytes
);
752 require_action( lpService
, exit
, err
= mStatus_NoMemoryErr
);
755 err
= translate_errno( ok
, GetLastError(), kUnknownErr
);
756 require_noerr( err
, exit
);
758 for ( i
= 0; i
< srvCount
; i
++ )
760 if ( wcscmp( lpService
[i
].lpServiceName
, L
"SharedAccess" ) == 0 )
762 if ( lpService
[i
].ServiceStatus
.dwCurrentState
== SERVICE_RUNNING
)
771 require_action( isRunning
, exit
, err
= kUnknownErr
);
773 // Check to see if we've managed the firewall.
774 // This package might have been installed, then
775 // the OS was upgraded to SP2 or above. If that's
776 // the case, then we need to manipulate the firewall
777 // so networking works correctly.
779 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
, &key
);
780 require_noerr( err
, exit
);
782 valueLen
= sizeof(DWORD
);
783 err
= RegQueryValueEx(key
, kServiceManageFirewall
, 0, &type
, (LPBYTE
) &value
, &valueLen
);
785 if ((err
!= ERROR_SUCCESS
) || (value
== 0))
787 wchar_t fullPath
[ MAX_PATH
];
790 // Get a full path to the executable
792 size
= GetModuleFileNameW( NULL
, fullPath
, sizeof( fullPath
) );
793 err
= translate_errno( size
> 0, (OSStatus
) GetLastError(), kPathErr
);
794 require_noerr( err
, exit
);
796 err
= mDNSAddToFirewall(fullPath
, kServiceFirewallName
);
797 require_noerr( err
, exit
);
800 err
= RegSetValueEx( key
, kServiceManageFirewall
, 0, REG_DWORD
, (const LPBYTE
) &value
, sizeof( DWORD
) );
801 require_noerr( err
, exit
);
818 CloseServiceHandle ( sc
);
826 //===========================================================================================================================
828 //===========================================================================================================================
830 static OSStatus
SetServiceInfo( SC_HANDLE inSCM
, LPCTSTR inServiceName
, LPCTSTR inDescription
)
835 SERVICE_DESCRIPTION description
;
836 SERVICE_FAILURE_ACTIONS actions
;
840 check( inServiceName
);
841 check( inDescription
);
846 // Open the database (if not provided) and lock it to prevent other access while re-configuring.
850 inSCM
= OpenSCManager( NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
851 err
= translate_errno( inSCM
, (OSStatus
) GetLastError(), kOpenErr
);
852 require_noerr( err
, exit
);
855 lock
= LockServiceDatabase( inSCM
);
856 err
= translate_errno( lock
, (OSStatus
) GetLastError(), kInUseErr
);
857 require_noerr( err
, exit
);
859 // Open a handle to the service.
861 service
= OpenService( inSCM
, inServiceName
, SERVICE_CHANGE_CONFIG
|SERVICE_START
);
862 err
= translate_errno( service
, (OSStatus
) GetLastError(), kNotFoundErr
);
863 require_noerr( err
, exit
);
865 // Change the description.
867 description
.lpDescription
= (LPTSTR
) inDescription
;
868 ok
= ChangeServiceConfig2( service
, SERVICE_CONFIG_DESCRIPTION
, &description
);
869 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kParamErr
);
870 require_noerr( err
, exit
);
872 actions
.dwResetPeriod
= INFINITE
;
873 actions
.lpRebootMsg
= NULL
;
874 actions
.lpCommand
= NULL
;
875 actions
.cActions
= 1;
876 actions
.lpsaActions
= &action
;
878 action
.Type
= SC_ACTION_RESTART
;
880 ok
= ChangeServiceConfig2( service
, SERVICE_CONFIG_FAILURE_ACTIONS
, &actions
);
881 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kParamErr
);
882 require_noerr( err
, exit
);
887 // Close the service and release the lock.
891 CloseServiceHandle( service
);
895 UnlockServiceDatabase( lock
);
900 //===========================================================================================================================
902 //===========================================================================================================================
904 static void ReportStatus( int inType
, const char *inFormat
, ... )
906 if( !gServiceQuietMode
)
910 va_start( args
, inFormat
);
911 if( gServiceEventSource
)
915 const char * array
[ 1 ];
917 vsprintf( s
, inFormat
, args
);
919 ok
= ReportEventA( gServiceEventSource
, (WORD
) inType
, 0, 0x20000001L
, NULL
, 1, 0, array
, NULL
);
920 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
926 n
= vfprintf( stderr
, inFormat
, args
);
933 //===========================================================================================================================
935 //===========================================================================================================================
937 static OSStatus
RunDirect( int argc
, LPTSTR argv
[] )
945 // Install a Console Control Handler to handle things like control-c signals.
947 ok
= SetConsoleCtrlHandler( ConsoleControlHandler
, TRUE
);
948 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
949 require_noerr( err
, exit
);
951 err
= ServiceSpecificInitialize( argc
, argv
);
952 require_noerr( err
, exit
);
955 // Run the service. This does not return until the service quits or is stopped.
957 ReportStatus( EVENTLOG_SUCCESS
, "Running \"%s\" service directly\n", kServiceName
);
959 err
= ServiceSpecificRun( argc
, argv
);
960 require_noerr( err
, exit
);
967 ServiceSpecificFinalize( argc
, argv
);
976 //===========================================================================================================================
978 //===========================================================================================================================
980 static void WINAPI
ServiceMain( DWORD argc
, LPTSTR argv
[] )
985 err
= ServiceSetupEventLogging();
988 err
= GetServiceParameters();
991 // Initialize the service status and register the service control handler with the name of the service.
993 gServiceStatus
.dwServiceType
= SERVICE_WIN32_SHARE_PROCESS
;
994 gServiceStatus
.dwCurrentState
= 0;
995 gServiceStatus
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
|SERVICE_ACCEPT_POWEREVENT
;
996 gServiceStatus
.dwWin32ExitCode
= NO_ERROR
;
997 gServiceStatus
.dwServiceSpecificExitCode
= NO_ERROR
;
998 gServiceStatus
.dwCheckPoint
= 0;
999 gServiceStatus
.dwWaitHint
= 0;
1001 gServiceStatusHandle
= RegisterServiceCtrlHandlerEx( argv
[ 0 ], ServiceControlHandler
, NULL
);
1002 err
= translate_errno( gServiceStatusHandle
, (OSStatus
) GetLastError(), kInUseErr
);
1003 require_noerr( err
, exit
);
1005 // Mark the service as starting.
1007 gServiceStatus
.dwCurrentState
= SERVICE_START_PENDING
;
1008 gServiceStatus
.dwCheckPoint
= 0;
1009 gServiceStatus
.dwWaitHint
= 5000; // 5 seconds
1010 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
1011 check_translated_errno( ok
, GetLastError(), kParamErr
);
1013 // Run the service. This does not return until the service quits or is stopped.
1015 err
= ServiceRun( (int) argc
, argv
);
1018 gServiceStatus
.dwWin32ExitCode
= ERROR_SERVICE_SPECIFIC_ERROR
;
1019 gServiceStatus
.dwServiceSpecificExitCode
= (DWORD
) err
;
1022 // Service-specific work is done so mark the service as stopped.
1024 gServiceStatus
.dwCurrentState
= SERVICE_STOPPED
;
1025 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
1026 check_translated_errno( ok
, GetLastError(), kParamErr
);
1028 // Note: The service status handle should not be closed according to Microsoft documentation.
1031 if( gServiceEventSource
)
1033 ok
= DeregisterEventSource( gServiceEventSource
);
1034 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
1035 gServiceEventSource
= NULL
;
1039 //===========================================================================================================================
1040 // ServiceSetupEventLogging
1041 //===========================================================================================================================
1043 static OSStatus
ServiceSetupEventLogging( void )
1048 DWORD typesSupported
;
1049 TCHAR path
[ MAX_PATH
];
1054 // Add/Open source name as a sub-key under the Application key in the EventLog registry key.
1056 s
= TEXT("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\") kServiceName
;
1057 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, s
, &key
);
1058 require_noerr( err
, exit
);
1060 // Add the name to the EventMessageFile subkey.
1063 GetModuleFileName( NULL
, path
, MAX_PATH
);
1064 n
= (DWORD
) ( ( StrLen( path
) + 1 ) * sizeof( TCHAR
) );
1065 err
= RegSetValueEx( key
, TEXT("EventMessageFile"), 0, REG_EXPAND_SZ
, (const LPBYTE
) path
, n
);
1066 require_noerr( err
, exit
);
1068 // Set the supported event types in the TypesSupported subkey.
1072 | EVENTLOG_ERROR_TYPE
1073 | EVENTLOG_WARNING_TYPE
1074 | EVENTLOG_INFORMATION_TYPE
1075 | EVENTLOG_AUDIT_SUCCESS
1076 | EVENTLOG_AUDIT_FAILURE
;
1077 err
= RegSetValueEx( key
, TEXT("TypesSupported"), 0, REG_DWORD
, (const LPBYTE
) &typesSupported
, sizeof( DWORD
) );
1078 require_noerr( err
, exit
);
1080 // Set up the event source.
1082 gServiceEventSource
= RegisterEventSource( NULL
, kServiceName
);
1083 err
= translate_errno( gServiceEventSource
, (OSStatus
) GetLastError(), kParamErr
);
1084 require_noerr( err
, exit
);
1094 //===========================================================================================================================
1095 // ServiceControlHandler
1096 //===========================================================================================================================
1098 static DWORD WINAPI
ServiceControlHandler( DWORD inControl
, DWORD inEventType
, LPVOID inEventData
, LPVOID inContext
)
1103 DEBUG_UNUSED( inEventData
);
1104 DEBUG_UNUSED( inContext
);
1109 case SERVICE_CONTROL_STOP
:
1110 dlog( kDebugLevelNotice
, DEBUG_NAME
"ServiceControlHandler: SERVICE_CONTROL_STOP\n" );
1116 case SERVICE_CONTROL_POWEREVENT
:
1118 if (inEventType
== PBT_APMSUSPEND
)
1120 mDNSCoreMachineSleep(&gMDNSRecord
, TRUE
);
1122 else if (inEventType
== PBT_APMRESUMESUSPEND
)
1124 mDNSCoreMachineSleep(&gMDNSRecord
, FALSE
);
1130 dlog( kDebugLevelNotice
, DEBUG_NAME
"ServiceControlHandler: event (0x%08X)\n", inControl
);
1134 if( setStatus
&& gServiceStatusHandle
)
1136 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
1137 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
1143 //===========================================================================================================================
1145 //===========================================================================================================================
1147 static OSStatus
ServiceRun( int argc
, LPTSTR argv
[] )
1153 DEBUG_UNUSED( argc
);
1154 DEBUG_UNUSED( argv
);
1156 initialized
= FALSE
;
1158 // Initialize the service-specific stuff and mark the service as running.
1160 err
= ServiceSpecificInitialize( argc
, argv
);
1161 require_noerr( err
, exit
);
1164 gServiceStatus
.dwCurrentState
= SERVICE_RUNNING
;
1165 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
1166 check_translated_errno( ok
, GetLastError(), kParamErr
);
1168 err
= CheckFirewall();
1173 gRetryFirewall
= TRUE
;
1176 // Run the service-specific stuff. This does not return until the service quits or is stopped.
1178 ReportStatus( EVENTLOG_INFORMATION_TYPE
, "mDNSResponder started\n" );
1179 err
= ServiceSpecificRun( argc
, argv
);
1180 ReportStatus( EVENTLOG_INFORMATION_TYPE
, "mDNSResponder stopped (%d)\n", err
);
1181 require_noerr( err
, exit
);
1183 // Service stopped. Clean up and we're done.
1188 ServiceSpecificFinalize( argc
, argv
);
1193 //===========================================================================================================================
1195 //===========================================================================================================================
1197 static void ServiceStop( void )
1202 // Signal the event to cause the service to exit.
1204 if( gServiceStatusHandle
)
1206 gServiceStatus
.dwCurrentState
= SERVICE_STOP_PENDING
;
1207 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
1208 check_translated_errno( ok
, GetLastError(), kParamErr
);
1211 err
= ServiceSpecificStop();
1217 #pragma mark == Service Specific ==
1220 //===========================================================================================================================
1221 // ServiceSpecificInitialize
1222 //===========================================================================================================================
1224 static OSStatus
ServiceSpecificInitialize( int argc
, LPTSTR argv
[] )
1228 DEBUG_UNUSED( argc
);
1229 DEBUG_UNUSED( argv
);
1231 memset( &gMDNSRecord
, 0, sizeof gMDNSRecord
);
1232 memset( &gPlatformStorage
, 0, sizeof gPlatformStorage
);
1234 gPlatformStorage
.idleThreadCallback
= udsIdle
;
1235 gPlatformStorage
.hostDescriptionChangedCallback
= HostDescriptionChanged
;
1237 InitializeCriticalSection(&gEventSourceLock
);
1239 gStopEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1240 err
= translate_errno( gStopEvent
, errno_compat(), kNoResourcesErr
);
1241 require_noerr( err
, exit
);
1243 err
= mDNS_Init( &gMDNSRecord
, &gPlatformStorage
, gRRCache
, RR_CACHE_SIZE
, mDNS_Init_AdvertiseLocalAddresses
, CoreCallback
, mDNS_Init_NoInitCallbackContext
);
1244 require_noerr( err
, exit
);
1246 err
= udsserver_init();
1247 require_noerr( err
, exit
);
1250 // <rdar://problem/4096464> Don't call SetLLRoute on loopback
1252 // Otherwise, set a route to link local addresses (169.254.0.0)
1255 if ( gServiceManageLLRouting
&& !gPlatformStorage
.registeredLoopback4
)
1257 SetLLRoute( &gMDNSRecord
);
1263 ServiceSpecificFinalize( argc
, argv
);
1268 //===========================================================================================================================
1269 // ServiceSpecificRun
1270 //===========================================================================================================================
1272 static OSStatus
ServiceSpecificRun( int argc
, LPTSTR argv
[] )
1277 DEBUG_UNUSED( argc
);
1278 DEBUG_UNUSED( argv
);
1280 // Main event loop. Process connection requests and state changes (i.e. quit).
1282 timeout
= ( gRetryFirewall
) ? kRetryFirewallPeriod
: INFINITE
;
1284 while( (result
= WaitForSingleObject( gStopEvent
, timeout
) ) != WAIT_OBJECT_0
)
1286 if ( result
== WAIT_TIMEOUT
)
1290 err
= CheckFirewall();
1297 // Unexpected wait result.
1298 dlog( kDebugLevelWarning
, DEBUG_NAME
"%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__
, result
);
1305 //===========================================================================================================================
1306 // ServiceSpecificStop
1307 //===========================================================================================================================
1309 static OSStatus
ServiceSpecificStop( void )
1314 ok
= SetEvent(gStopEvent
);
1315 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
1316 require_noerr( err
, exit
);
1321 //===========================================================================================================================
1322 // ServiceSpecificFinalize
1323 //===========================================================================================================================
1325 static void ServiceSpecificFinalize( int argc
, LPTSTR argv
[] )
1327 DEBUG_UNUSED( argc
);
1328 DEBUG_UNUSED( argv
);
1331 // clean up any open sessions
1333 while (gEventSources
.Head
)
1335 EventSourceFinalize((Win32EventSource
*) gEventSources
.Head
);
1338 // give a chance for the udsserver code to clean up
1343 // and finally close down the mDNSCore
1345 mDNS_Close(&gMDNSRecord
);
1348 // clean up the event sources mutex...no one should be using it now
1350 DeleteCriticalSection(&gEventSourceLock
);
1355 CoreCallback(mDNS
* const inMDNS
, mStatus status
)
1357 if (status
== mStatus_ConfigChanged
)
1360 // <rdar://problem/4096464> Don't call SetLLRoute on loopback
1362 // Otherwise, set a route to link local addresses (169.254.0.0)
1365 if ( gServiceManageLLRouting
&& !inMDNS
->p
->registeredLoopback4
)
1367 SetLLRoute( inMDNS
);
1374 udsIdle(mDNS
* const inMDNS
, mDNSs32 interval
)
1376 DEBUG_UNUSED( inMDNS
);
1379 // rdar://problem/3697326
1381 // udsserver_idle wasn't being locked. This resulted
1382 // in multiple threads contesting for the all_requests
1383 // data structure in uds_daemon.c
1385 mDNSPlatformLock(&gMDNSRecord
);
1387 interval
= udsserver_idle(interval
);
1389 mDNSPlatformUnlock(&gMDNSRecord
);
1396 HostDescriptionChanged(mDNS
* const inMDNS
)
1398 DEBUG_UNUSED( inMDNS
);
1400 udsserver_handle_configchange();
1404 mDNSlocal
unsigned WINAPI
1405 udsSocketThread(LPVOID inParam
)
1407 Win32EventSource
* source
= (Win32EventSource
*) inParam
;
1408 DWORD threadID
= GetCurrentThreadId();
1413 bool locked
= false;
1416 waitCount
= source
->waitCount
;
1417 waitList
[0] = source
->waitList
[0];
1418 waitList
[1] = source
->waitList
[1];
1419 done
= (bool) (source
->flags
& EventSourceFinalized
);
1425 result
= WaitForMultipleObjects(waitCount
, waitList
, FALSE
, INFINITE
);
1427 mDNSPlatformLock(&gMDNSRecord
);
1430 // <rdar://problem/3838237>
1432 // Look up the source by the thread id. This will ensure that the
1433 // source is still extant. It could already have been deleted
1434 // by the processing thread.
1439 for (source
= gEventSources
.Head
; source
; source
= source
->next
)
1441 if (source
->threadID
== threadID
)
1447 EventSourceUnlock();
1457 if (result
== WAIT_OBJECT_0
)
1459 source
->callback(source
->context
);
1464 else if (result
== WAIT_OBJECT_0
+ 1)
1467 // this is a bit of a hack. we want to clean up the internal data structures
1468 // so we'll go in here and it will clean up for us
1470 shutdown(source
->sock
, 2);
1471 source
->callback(source
->context
);
1477 // Unexpected wait result.
1478 dlog( kDebugLevelWarning
, DEBUG_NAME
"%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__
, result
);
1482 done
= (bool) (source
->flags
& EventSourceFinalized
);
1484 mDNSPlatformUnlock(&gMDNSRecord
);
1489 source
->flags
|= EventSourceFlagsThreadDone
;
1490 safeToClose
= !( source
->flags
& EventSourceFlagsNoClose
);
1491 EventSourceUnlock();
1495 EventSourceFinalize( source
);
1502 mDNSPlatformUnlock(&gMDNSRecord
);
1505 _endthreadex_compat( (unsigned) err
);
1506 return( (unsigned) err
);
1511 udsSupportAddFDToEventLoop( SocketRef fd
, udsEventCallback callback
, void *context
)
1513 Win32EventSource
* newSource
;
1517 newSource
= malloc(sizeof(Win32EventSource
));
1518 require_action( newSource
, exit
, err
= mStatus_NoMemoryErr
);
1519 memset(newSource
, 0, sizeof(Win32EventSource
));
1521 newSource
->flags
= 0;
1522 newSource
->sock
= (SOCKET
) fd
;
1523 newSource
->callback
= callback
;
1524 newSource
->context
= context
;
1526 newSource
->socketEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1527 err
= translate_errno( newSource
->socketEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1528 require_noerr( err
, exit
);
1530 newSource
->closeEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1531 err
= translate_errno( newSource
->closeEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1532 require_noerr( err
, exit
);
1534 err
= WSAEventSelect(newSource
->sock
, newSource
->socketEvent
, FD_ACCEPT
|FD_READ
|FD_CLOSE
);
1535 err
= translate_errno( err
== 0, errno_compat(), kNoResourcesErr
);
1536 require_noerr( err
, exit
);
1538 newSource
->waitCount
= 0;
1539 newSource
->waitList
[ newSource
->waitCount
++ ] = newSource
->socketEvent
;
1540 newSource
->waitList
[ newSource
->waitCount
++ ] = newSource
->closeEvent
;
1547 // add the event source to the end of the list, while checking
1548 // to see if the list needs to be initialized
1550 if ( gEventSources
.LinkOffset
== 0)
1552 InitLinkedList( &gEventSources
, offsetof( Win32EventSource
, next
));
1555 AddToTail( &gEventSources
, newSource
);
1558 // no longer using the list
1560 EventSourceUnlock();
1562 // Create thread with _beginthreadex() instead of CreateThread() to avoid memory leaks when using static run-time
1563 // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
1564 // Create the thread suspended then resume it so the thread handle and ID are valid before the thread starts running.
1565 newSource
->threadHandle
= (HANDLE
) _beginthreadex_compat( NULL
, 0, udsSocketThread
, newSource
, CREATE_SUSPENDED
, &newSource
->threadID
);
1566 err
= translate_errno( newSource
->threadHandle
, (mStatus
) GetLastError(), kUnknownErr
);
1567 require_noerr( err
, exit
);
1569 result
= ResumeThread( newSource
->threadHandle
);
1570 err
= translate_errno( result
!= (DWORD
) -1, errno_compat(), kNoResourcesErr
);
1571 require_noerr( err
, exit
);
1575 if (err
&& newSource
)
1577 EventSourceFinalize(newSource
);
1585 udsSupportRemoveFDFromEventLoop( SocketRef fd
) // Note: This also CLOSES the socket
1587 Win32EventSource
* source
;
1588 mStatus err
= mStatus_NoError
;
1591 // find the event source
1595 for (source
= gEventSources
.Head
; source
; source
= source
->next
)
1597 if (source
->sock
== (SOCKET
) fd
)
1604 // if we found him, finalize him
1608 EventSourceFinalize(source
);
1612 // done with the list
1614 EventSourceUnlock();
1622 mDNSexport
void RecordUpdatedNiceLabel(mDNS
*const m
, mDNSs32 delay
)
1631 EventSourceFinalize(Win32EventSource
* source
)
1635 Win32EventSource
* inserted
;
1644 // Find the session in the list.
1649 for( inserted
= (Win32EventSource
*) gEventSources
.Head
; inserted
; inserted
= inserted
->next
)
1651 if( inserted
== source
)
1656 require_action( inserted
, exit
, err
= kNotFoundErr
);
1659 // note that we've had finalize called
1661 source
->flags
|= EventSourceFinalized
;
1663 // If we're being called from the same thread as the session (e.g. message callback is closing the session) then
1664 // we must defer the close until the thread is done because the thread is still using the session object.
1667 threadID
= GetCurrentThreadId();
1668 sameThread
= source
->threadHandle
&& ( threadID
== source
->threadID
);
1669 if( sameThread
&& !( source
->flags
& EventSourceFlagsThreadDone
) )
1671 source
->flags
&= ~EventSourceFlagsNoClose
;
1675 // If the thread we're not being called from the session thread, but the thread has already marked itself as
1676 // as done (e.g. session closed from something like a peer disconnect and at the same time the client also
1677 // tried to close) then we only want to continue with the close if the thread is not going to close itself.
1679 if( !sameThread
&& ( source
->flags
& EventSourceFlagsThreadDone
) && !( source
->flags
& EventSourceFlagsNoClose
) )
1684 // Signal a close so the thread exits.
1686 if( source
->closeEvent
)
1688 ok
= SetEvent( source
->closeEvent
);
1689 check_translated_errno( ok
, errno_compat(), kUnknownErr
);
1697 source
->flags
|= EventSourceFlagsNoClose
;
1699 // Remove the session from the list.
1700 RemoveFromList(&gEventSources
, source
);
1702 EventSourceUnlock();
1705 // Wait for the thread to exit. Give up after 3 seconds to handle a hung thread.
1707 if( source
->threadHandle
&& ( threadID
!= source
->threadID
) )
1709 result
= WaitForSingleObject( source
->threadHandle
, 3 * 1000 );
1710 check_translated_errno( result
== WAIT_OBJECT_0
, (OSStatus
) GetLastError(), result
);
1713 // Release the thread.
1715 if( source
->threadHandle
)
1717 ok
= CloseHandle( source
->threadHandle
);
1718 check_translated_errno( ok
, errno_compat(), kUnknownErr
);
1719 source
->threadHandle
= NULL
;
1722 // Release the socket event.
1724 if( source
->socketEvent
)
1726 ok
= CloseHandle( source
->socketEvent
);
1727 check_translated_errno( ok
, errno_compat(), kUnknownErr
);
1728 source
->socketEvent
= NULL
;
1731 // Release the close event.
1733 if( source
->closeEvent
)
1735 ok
= CloseHandle( source
->closeEvent
);
1736 check_translated_errno( ok
, errno_compat(), kUnknownErr
);
1737 source
->closeEvent
= NULL
;
1740 // Release the memory used by the object.
1745 dlog( kDebugLevelNotice
, DEBUG_NAME
"session closed\n" );
1751 EventSourceUnlock();
1761 EnterCriticalSection(&gEventSourceLock
);
1768 LeaveCriticalSection(&gEventSourceLock
);
1772 //===========================================================================================================================
1774 //===========================================================================================================================
1777 HaveRoute( PMIB_IPFORWARDROW rowExtant
, unsigned long addr
)
1779 PMIB_IPFORWARDTABLE pIpForwardTable
= NULL
;
1781 BOOL bOrder
= FALSE
;
1784 unsigned long int i
;
1787 // Find out how big our buffer needs to be.
1789 err
= GetIpForwardTable(NULL
, &dwSize
, bOrder
);
1790 require_action( err
== ERROR_INSUFFICIENT_BUFFER
, exit
, err
= kUnknownErr
);
1793 // Allocate the memory for the table
1795 pIpForwardTable
= (PMIB_IPFORWARDTABLE
) malloc( dwSize
);
1796 require_action( pIpForwardTable
, exit
, err
= kNoMemoryErr
);
1799 // Now get the table.
1801 err
= GetIpForwardTable(pIpForwardTable
, &dwSize
, bOrder
);
1802 require_noerr( err
, exit
);
1805 // Search for the row in the table we want.
1807 for ( i
= 0; i
< pIpForwardTable
->dwNumEntries
; i
++)
1809 if ( pIpForwardTable
->table
[i
].dwForwardDest
== addr
)
1811 memcpy( rowExtant
, &(pIpForwardTable
->table
[i
]), sizeof(*rowExtant
) );
1819 if ( pIpForwardTable
!= NULL
)
1821 free(pIpForwardTable
);
1828 //===========================================================================================================================
1830 //===========================================================================================================================
1833 IsValidAddress( const char * addr
)
1835 return ( addr
&& ( strcmp( addr
, "0.0.0.0" ) != 0 ) ) ? true : false;
1839 //===========================================================================================================================
1841 //===========================================================================================================================
1844 SetLLRoute( mDNS
* const inMDNS
)
1847 MIB_IPFORWARDROW rowExtant
;
1849 MIB_IPFORWARDROW row
;
1852 ZeroMemory(&row
, sizeof(row
));
1854 err
= GetRouteDestination(&ifIndex
, &row
.dwForwardNextHop
);
1855 require_noerr( err
, exit
);
1856 row
.dwForwardDest
= inet_addr(kLLNetworkAddr
);
1857 row
.dwForwardIfIndex
= ifIndex
;
1858 row
.dwForwardMask
= inet_addr(kLLNetworkAddrMask
);
1859 row
.dwForwardType
= 3;
1860 row
.dwForwardProto
= MIB_IPPROTO_NETMGMT
;
1861 row
.dwForwardAge
= 0;
1862 row
.dwForwardPolicy
= 0;
1863 row
.dwForwardMetric1
= 30;
1864 row
.dwForwardMetric2
= (DWORD
) - 1;
1865 row
.dwForwardMetric3
= (DWORD
) - 1;
1866 row
.dwForwardMetric4
= (DWORD
) - 1;
1867 row
.dwForwardMetric5
= (DWORD
) - 1;
1872 // check to make sure we don't already have a route
1874 if ( HaveRoute( &rowExtant
, inet_addr( kLLNetworkAddr
) ) )
1877 // set the age to 0 so that we can do a memcmp.
1879 rowExtant
.dwForwardAge
= 0;
1882 // check to see if this route is the same as our route
1884 if (memcmp(&row
, &rowExtant
, sizeof(row
)) != 0)
1887 // if it isn't then delete this entry
1889 DeleteIpForwardEntry(&rowExtant
);
1894 // else it is, so we don't want to create another route
1900 if (addRoute
&& row
.dwForwardNextHop
)
1902 err
= CreateIpForwardEntry(&row
);
1904 require_noerr( err
, exit
);
1908 // Now we want to see if we should install a default route for this interface.
1909 // We want to do this if the following are true:
1911 // 1. This interface has a link-local address
1912 // 2. This is the only IPv4 interface
1915 if ( ( row
.dwForwardNextHop
& 0xFFFF ) == row
.dwForwardDest
)
1917 mDNSInterfaceData
* ifd
;
1918 int numLinkLocalInterfaces
= 0;
1919 int numInterfaces
= 0;
1921 for ( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
1923 if ( ifd
->defaultAddr
.type
== mDNSAddrType_IPv4
)
1927 if ( ( ifd
->interfaceInfo
.ip
.ip
.v4
.b
[0] == 169 ) && ( ifd
->interfaceInfo
.ip
.ip
.v4
.b
[1] == 254 ) )
1929 numLinkLocalInterfaces
++;
1934 row
.dwForwardDest
= 0;
1935 row
.dwForwardIfIndex
= ifIndex
;
1936 row
.dwForwardMask
= 0;
1937 row
.dwForwardType
= 3;
1938 row
.dwForwardProto
= MIB_IPPROTO_NETMGMT
;
1939 row
.dwForwardAge
= 0;
1940 row
.dwForwardPolicy
= 0;
1941 row
.dwForwardMetric1
= 20;
1942 row
.dwForwardMetric2
= (DWORD
) - 1;
1943 row
.dwForwardMetric3
= (DWORD
) - 1;
1944 row
.dwForwardMetric4
= (DWORD
) - 1;
1945 row
.dwForwardMetric5
= (DWORD
) - 1;
1947 if ( numInterfaces
== numLinkLocalInterfaces
)
1949 if ( !HaveRoute( &row
, 0 ) )
1951 err
= CreateIpForwardEntry(&row
);
1952 require_noerr( err
, exit
);
1957 DeleteIpForwardEntry( &row
);
1967 //===========================================================================================================================
1968 // GetRouteDestination
1969 //===========================================================================================================================
1972 GetRouteDestination(DWORD
* ifIndex
, DWORD
* address
)
1975 IP_ADAPTER_INFO
* pAdapterInfo
= NULL
;
1976 IP_ADAPTER_INFO
* pAdapter
= NULL
;
1978 mDNSBool done
= mDNSfalse
;
1982 // GetBestInterface will fail if there is no default gateway
1983 // configured. If that happens, we will just take the first
1984 // interface in the list. MSDN support says there is no surefire
1985 // way to manually determine what the best interface might
1986 // be for a particular network address.
1988 ia
.s_addr
= inet_addr(kLLNetworkAddr
);
1989 err
= GetBestInterface(*(IPAddr
*) &ia
, ifIndex
);
1997 // Make an initial call to GetAdaptersInfo to get
1998 // the necessary size into the bufLen variable
2000 err
= GetAdaptersInfo( NULL
, &bufLen
);
2001 require_action( err
== ERROR_BUFFER_OVERFLOW
, exit
, err
= kUnknownErr
);
2003 pAdapterInfo
= (IP_ADAPTER_INFO
*) malloc( bufLen
);
2004 require_action( pAdapterInfo
, exit
, err
= kNoMemoryErr
);
2006 err
= GetAdaptersInfo( pAdapterInfo
, &bufLen
);
2007 require_noerr( err
, exit
);
2009 pAdapter
= pAdapterInfo
;
2012 // <rdar://problem/3718122>
2014 // Look for the Nortel VPN virtual interface. This interface
2015 // is identified by it's unique MAC address: 44-45-53-54-42-00
2017 // If the interface is active (i.e., has a non-zero IP Address),
2018 // then we want to disable routing table modifications.
2022 if ((pAdapter
->Type
== MIB_IF_TYPE_ETHERNET
) &&
2023 (pAdapter
->AddressLength
== 6) &&
2024 (pAdapter
->Address
[0] == 0x44) &&
2025 (pAdapter
->Address
[1] == 0x45) &&
2026 (pAdapter
->Address
[2] == 0x53) &&
2027 (pAdapter
->Address
[3] == 0x54) &&
2028 (pAdapter
->Address
[4] == 0x42) &&
2029 (pAdapter
->Address
[5] == 0x00) &&
2030 (inet_addr( pAdapter
->IpAddressList
.IpAddress
.String
) != 0))
2035 pAdapter
= pAdapter
->Next
;
2040 pAdapter
= pAdapterInfo
;
2045 // If we don't have an interface selected, choose the first one that is of type ethernet and
2046 // has a valid IP Address
2048 if ((pAdapter
->Type
== MIB_IF_TYPE_ETHERNET
) && ( IsValidAddress( pAdapter
->IpAddressList
.IpAddress
.String
) ) && (!(*ifIndex
) || (pAdapter
->Index
== (*ifIndex
))))
2050 *address
= inet_addr( pAdapter
->IpAddressList
.IpAddress
.String
);
2051 *ifIndex
= pAdapter
->Index
;
2056 pAdapter
= pAdapter
->Next
;
2059 // If we found the right interface, or we weren't trying to find a specific interface then we're done
2061 if ( !err
|| !( *ifIndex
) )
2066 // Otherwise, try again by wildcarding the interface
2076 if ( pAdapterInfo
!= NULL
)
2078 free( pAdapterInfo
);