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.42 2007/02/14 01:58:19 cheshire
21 <rdar://problem/4995831> Don't delete Unix Domain Socket on exit if we didn't create it on startup
23 Revision 1.41 2007/02/06 19:06:49 cheshire
24 <rdar://problem/3956518> Need to go native with launchd
26 Revision 1.40 2007/01/05 05:46:08 cheshire
27 Add mDNS *const m parameter to udsserver_handle_configchange()
29 Revision 1.39 2006/08/14 23:26:07 cheshire
30 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
32 Revision 1.38 2005/10/05 20:55:15 herscher
33 <rdar://problem/4096464> Don't call SetLLRoute on loopback interface
35 Revision 1.37 2005/10/05 18:05:28 herscher
36 <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.
38 Revision 1.36 2005/09/11 22:12:42 herscher
39 <rdar://problem/4247793> Remove dependency on WMI. Ensure that the Windows firewall is turned on before trying to configure it.
41 Revision 1.35 2005/06/30 18:29:49 shersche
42 <rdar://problem/4090059> Don't overwrite the localized service description text
44 Revision 1.34 2005/04/22 07:34:23 shersche
45 Check an interface's address and make sure it's valid before using it to set link-local routes.
47 Revision 1.33 2005/04/13 17:48:23 shersche
48 <rdar://problem/4079667> Make sure there is only one default route for link-local addresses.
50 Revision 1.32 2005/04/06 01:32:05 shersche
51 Remove default route for link-local addressing when another interface comes up with a routable IPv4 address
53 Revision 1.31 2005/04/06 01:00:11 shersche
54 <rdar://problem/4080127> GetFullPathName() should be passed the number of TCHARs in the path buffer, not the size in bytes of the path buffer.
56 Revision 1.30 2005/04/06 00:52:43 shersche
57 <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.
59 Revision 1.29 2005/03/06 05:21:56 shersche
60 <rdar://problem/4037635> Fix corrupt UTF-8 name when non-ASCII system name used, enabled unicode support
62 Revision 1.28 2005/03/03 02:27:24 shersche
63 Include the RegNames.h header file for names of registry keys
65 Revision 1.27 2005/03/02 20:12:59 shersche
68 Revision 1.26 2005/02/15 08:00:27 shersche
69 <rdar://problem/4007151> Update name
71 Revision 1.25 2005/02/10 22:35:36 cheshire
72 <rdar://problem/3727944> Update name
74 Revision 1.24 2005/01/27 20:02:43 cheshire
75 udsSupportRemoveFDFromEventLoop() needs to close the SocketRef as well
77 Revision 1.23 2005/01/25 08:14:15 shersche
78 Change CacheRecord to CacheEntity
80 Revision 1.22 2004/12/10 13:18:40 cheshire
81 Create no-op function RecordUpdatedNiceLabel(), required by uds_daemon.c
83 Revision 1.21 2004/11/10 04:03:41 shersche
84 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.
86 Revision 1.20 2004/10/14 21:44:05 shersche
87 <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.
90 Revision 1.19 2004/10/12 17:59:55 shersche
91 <rdar://problem/3718122> Disable routing table modifications when Nortel VPN adapter is active
94 Revision 1.18 2004/10/11 21:57:50 shersche
95 <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.
98 Revision 1.17 2004/09/17 01:08:58 cheshire
99 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
100 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
101 declared in that file are ONLY appropriate to single-address-space embedded applications.
102 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
104 Revision 1.16 2004/09/16 18:49:34 shersche
105 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.
107 Revision 1.15 2004/09/15 17:13:33 shersche
110 Revision 1.14 2004/09/15 09:37:25 shersche
111 Add SharedAccess to dependency list, call CheckFirewall after sending status back to SCM
113 Revision 1.13 2004/09/13 07:35:10 shersche
114 <rdar://problem/3762235> Add mDNSResponder to Windows Firewall application list if SP2 is detected and app hasn't been added before
117 Revision 1.12 2004/09/11 21:18:32 shersche
118 <rdar://problem/3779502> Add route to ARP everything when a 169.254.x.x address is selected
121 Revision 1.11 2004/09/11 05:39:19 shersche
122 <rdar://problem/3780203> Detect power managment state changes, calling mDNSCoreMachineSleep(m, true) on sleep, and mDNSCoreMachineSleep(m, false) on resume
125 Revision 1.10 2004/08/16 21:45:24 shersche
126 Use the full pathname of executable when calling CreateService()
127 Submitted by: prepin@zetron.com
129 Revision 1.9 2004/08/11 01:59:41 cheshire
130 Remove "mDNS *globalInstance" parameter from udsserver_init()
132 Revision 1.8 2004/08/05 05:40:05 shersche
133 <rdar://problem/3751566> Only invoke SetConsoleCtrlHandler when running directly from command line.
134 <rdar://problem/3751481> Invoke udsserver_handle_configchange() when the computer description changes
135 Bug #: 3751481, 3751566
137 Revision 1.7 2004/07/26 05:35:07 shersche
138 ignore non-enet interfaces when setting up link-local routing
140 Revision 1.6 2004/07/20 06:48:26 shersche
141 <rdar://problem/3718122> Allow registry entries to dictate whether to manage link local routing
144 Revision 1.5 2004/07/09 19:08:07 shersche
145 <rdar://problem/3713762> ServiceSetupEventLogging() errors are handled gracefully
148 Revision 1.4 2004/06/24 20:58:15 shersche
149 Fix compiler error in Release build
150 Submitted by: herscher
152 Revision 1.3 2004/06/24 15:28:53 shersche
153 Automatically setup routes to link-local addresses upon interface list change events.
154 Submitted by: herscher
156 Revision 1.2 2004/06/23 16:56:00 shersche
157 <rdar://problem/3697326> locked call to udsserver_idle().
159 Submitted by: herscher
161 Revision 1.1 2004/06/18 04:16:41 rpantos
164 Revision 1.1 2004/01/30 02:58:39 bradley
165 mDNSResponder Windows Service. Provides global Bonjour support with an IPC interface.
173 #include "CommonServices.h"
174 #include "DebugServices.h"
175 #include "RegNames.h"
177 #include "uds_daemon.h"
178 #include "GenLinkedList.h"
180 #include "Resource.h"
182 #include "mDNSEmbeddedAPI.h"
183 #include "mDNSWin32.h"
185 #include "Firewall.h"
187 #if( !TARGET_OS_WINDOWS_CE )
190 #include <ipExport.h>
191 #include <iphlpapi.h>
196 #pragma mark == Constants ==
199 //===========================================================================================================================
201 //===========================================================================================================================
203 #define DEBUG_NAME "[Server] "
204 #define kServiceFirewallName L"Bonjour"
205 #define kServiceDependencies TEXT("Tcpip\0\0")
206 #define kDNSServiceCacheEntryCountDefault 512
207 #define kRetryFirewallPeriod 30 * 1000
209 #define RR_CACHE_SIZE 500
210 static CacheEntity gRRCache
[RR_CACHE_SIZE
];
212 #pragma mark == Structures ==
215 //===========================================================================================================================
217 //===========================================================================================================================
218 //---------------------------------------------------------------------------------------------------------------------------
219 /*! @typedef EventSourceFlags
221 @abstract Session flags.
223 @constant EventSourceFlagsNone No flags.
224 @constant EventSourceFlagsThreadDone Thread is no longer active.
225 @constant EventSourceFlagsNoClose Do not close the session when the thread exits.
226 @constant EventSourceFinalized Finalize has been called for this session
229 typedef uint32_t EventSourceFlags
;
231 #define EventSourceFlagsNone 0
232 #define EventSourceFlagsThreadDone ( 1 << 2 )
233 #define EventSourceFlagsNoClose ( 1 << 3 )
234 #define EventSourceFinalized ( 1 << 4 )
237 typedef struct Win32EventSource
239 EventSourceFlags flags
;
244 udsEventCallback callback
;
249 struct Win32EventSource
* next
;
254 #pragma mark == Prototypes ==
257 //===========================================================================================================================
259 //===========================================================================================================================
261 int __cdecl
wmain( int argc
, LPTSTR argv
[] );
263 int __cdecl
main( int argc
, char *argv
[] );
265 static void Usage( void );
266 static BOOL WINAPI
ConsoleControlHandler( DWORD inControlEvent
);
267 static OSStatus
InstallService( LPCTSTR inName
, LPCTSTR inDisplayName
, LPCTSTR inDescription
, LPCTSTR inPath
);
268 static OSStatus
RemoveService( LPCTSTR inName
);
269 static OSStatus
SetServiceParameters();
270 static OSStatus
GetServiceParameters();
271 static OSStatus
CheckFirewall();
272 static OSStatus
SetServiceInfo( SC_HANDLE inSCM
, LPCTSTR inServiceName
, LPCTSTR inDescription
);
273 static void ReportStatus( int inType
, const char *inFormat
, ... );
274 static OSStatus
RunDirect( int argc
, LPTSTR argv
[] );
276 static void WINAPI
ServiceMain( DWORD argc
, LPTSTR argv
[] );
277 static OSStatus
ServiceSetupEventLogging( void );
278 static DWORD WINAPI
ServiceControlHandler( DWORD inControl
, DWORD inEventType
, LPVOID inEventData
, LPVOID inContext
);
280 static OSStatus
ServiceRun( int argc
, LPTSTR argv
[] );
281 static void ServiceStop( void );
283 static OSStatus
ServiceSpecificInitialize( int argc
, LPTSTR argv
[] );
284 static OSStatus
ServiceSpecificRun( int argc
, LPTSTR argv
[] );
285 static OSStatus
ServiceSpecificStop( void );
286 static void ServiceSpecificFinalize( int argc
, LPTSTR argv
[] );
287 static mStatus
EventSourceFinalize(Win32EventSource
* source
);
288 static void EventSourceLock();
289 static void EventSourceUnlock();
290 static mDNSs32
udsIdle(mDNS
* const inMDNS
, mDNSs32 interval
);
291 static void CoreCallback(mDNS
* const inMDNS
, mStatus result
);
292 static void HostDescriptionChanged(mDNS
* const inMDNS
);
293 static OSStatus
GetRouteDestination(DWORD
* ifIndex
, DWORD
* address
);
294 static OSStatus
SetLLRoute( mDNS
* const inMDNS
);
295 static bool HaveRoute( PMIB_IPFORWARDROW rowExtant
, unsigned long addr
);
296 static bool IsValidAddress( const char * addr
);
299 # define StrLen(X) wcslen(X)
300 # define StrCmp(X,Y) wcscmp(X,Y)
302 # define StrLen(X) strlen(X)
303 # define StrCmp(X,Y) strcmp(X,Y)
307 #define kLLNetworkAddr "169.254.0.0"
308 #define kLLNetworkAddrMask "255.255.0.0"
311 #include "mDNSEmbeddedAPI.h"
314 #pragma mark == Globals ==
317 //===========================================================================================================================
319 //===========================================================================================================================
320 #define gMDNSRecord mDNSStorage
321 DEBUG_LOCAL mDNS_PlatformSupport gPlatformStorage
;
322 DEBUG_LOCAL BOOL gServiceQuietMode
= FALSE
;
323 DEBUG_LOCAL SERVICE_TABLE_ENTRY gServiceDispatchTable
[] =
325 { kServiceName
, ServiceMain
},
328 DEBUG_LOCAL SERVICE_STATUS gServiceStatus
;
329 DEBUG_LOCAL SERVICE_STATUS_HANDLE gServiceStatusHandle
= NULL
;
330 DEBUG_LOCAL HANDLE gServiceEventSource
= NULL
;
331 DEBUG_LOCAL
bool gServiceAllowRemote
= false;
332 DEBUG_LOCAL
int gServiceCacheEntryCount
= 0; // 0 means to use the DNS-SD default.
333 DEBUG_LOCAL
bool gServiceManageLLRouting
= true;
334 DEBUG_LOCAL
int gWaitCount
= 0;
335 DEBUG_LOCAL HANDLE
* gWaitList
= NULL
;
336 DEBUG_LOCAL HANDLE gStopEvent
= NULL
;
337 DEBUG_LOCAL CRITICAL_SECTION gEventSourceLock
;
338 DEBUG_LOCAL GenLinkedList gEventSources
;
339 DEBUG_LOCAL BOOL gRetryFirewall
= FALSE
;
346 //===========================================================================================================================
348 //===========================================================================================================================
350 int __cdecl
wmain( int argc
, wchar_t * argv
[] )
352 int __cdecl
main( int argc
, char *argv
[] )
360 debug_initialize( kDebugOutputTypeMetaConsole
);
361 debug_set_property( kDebugPropertyTagPrintLevel
, kDebugLevelVerbose
);
363 // Default to automatically starting the service dispatcher if no extra arguments are specified.
365 start
= ( argc
<= 1 );
369 for( i
= 1; i
< argc
; ++i
)
371 if( StrCmp( argv
[ i
], TEXT("-install") ) == 0 ) // Install
376 LoadString( GetModuleHandle( NULL
), IDS_SERVICE_DESCRIPTION
, desc
, sizeof( desc
) );
377 err
= InstallService( kServiceName
, kServiceName
, desc
, argv
[0] );
380 ReportStatus( EVENTLOG_ERROR_TYPE
, "install service failed (%d)\n", err
);
384 else if( StrCmp( argv
[ i
], TEXT("-remove") ) == 0 ) // Remove
386 err
= RemoveService( kServiceName
);
389 ReportStatus( EVENTLOG_ERROR_TYPE
, "remove service failed (%d)\n", err
);
393 else if( StrCmp( argv
[ i
], TEXT("-start") ) == 0 ) // Start
397 else if( StrCmp( argv
[ i
], TEXT("-server") ) == 0 ) // Server
399 err
= RunDirect( argc
, argv
);
402 ReportStatus( EVENTLOG_ERROR_TYPE
, "run service directly failed (%d)\n", err
);
406 else if( StrCmp( argv
[ i
], TEXT("-q") ) == 0 ) // Quiet Mode (toggle)
408 gServiceQuietMode
= !gServiceQuietMode
;
410 else if( ( StrCmp( argv
[ i
], TEXT("-help") ) == 0 ) || // Help
411 ( StrCmp( argv
[ i
], TEXT("-h") ) == 0 ) )
425 // Start the service dispatcher if requested. This does not return until all services have terminated. If any
426 // global initialization is needed, it should be done before starting the service dispatcher, but only if it
427 // will take less than 30 seconds. Otherwise, use a separate thread for it and start the dispatcher immediately.
431 ok
= StartServiceCtrlDispatcher( gServiceDispatchTable
);
432 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kInUseErr
);
435 ReportStatus( EVENTLOG_ERROR_TYPE
, "start service dispatcher failed (%d)\n", err
);
442 dlog( kDebugLevelTrace
, DEBUG_NAME
"exited (%d %m)\n", err
, err
);
446 //===========================================================================================================================
448 //===========================================================================================================================
450 static void Usage( void )
452 fprintf( stderr
, "\n" );
453 fprintf( stderr
, "mDNSResponder 1.0d1\n" );
454 fprintf( stderr
, "\n" );
455 fprintf( stderr
, " <no args> Runs the service normally\n" );
456 fprintf( stderr
, " -install Creates the service and starts it\n" );
457 fprintf( stderr
, " -remove Stops the service and deletes it\n" );
458 fprintf( stderr
, " -start Starts the service dispatcher after processing all other arguments\n" );
459 fprintf( stderr
, " -server Runs the service directly as a server (for debugging)\n" );
460 fprintf( stderr
, " -q Toggles Quiet Mode (no events or output)\n" );
461 fprintf( stderr
, " -remote Allow remote connections\n" );
462 fprintf( stderr
, " -cache n Number of mDNS cache entries (defaults to %d)\n", kDNSServiceCacheEntryCountDefault
);
463 fprintf( stderr
, " -h[elp] Display Help/Usage\n" );
464 fprintf( stderr
, "\n" );
467 //===========================================================================================================================
468 // ConsoleControlHandler
469 //===========================================================================================================================
471 static BOOL WINAPI
ConsoleControlHandler( DWORD inControlEvent
)
477 switch( inControlEvent
)
480 case CTRL_BREAK_EVENT
:
481 case CTRL_CLOSE_EVENT
:
482 case CTRL_LOGOFF_EVENT
:
483 case CTRL_SHUTDOWN_EVENT
:
484 err
= ServiceSpecificStop();
485 require_noerr( err
, exit
);
498 //===========================================================================================================================
500 //===========================================================================================================================
502 static OSStatus
InstallService( LPCTSTR inName
, LPCTSTR inDisplayName
, LPCTSTR inDescription
, LPCTSTR inPath
)
508 TCHAR fullPath
[ MAX_PATH
];
515 // Get a full path to the executable since a relative path may have been specified.
517 size
= GetFullPathName( inPath
, MAX_PATH
, fullPath
, &namePtr
);
518 err
= translate_errno( size
> 0, (OSStatus
) GetLastError(), kPathErr
);
519 require_noerr( err
, exit
);
521 // Create the service and start it.
523 scm
= OpenSCManager( NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
524 err
= translate_errno( scm
, (OSStatus
) GetLastError(), kOpenErr
);
525 require_noerr( err
, exit
);
527 service
= CreateService( scm
, inName
, inDisplayName
, SERVICE_ALL_ACCESS
, SERVICE_WIN32_SHARE_PROCESS
,
528 SERVICE_AUTO_START
, SERVICE_ERROR_NORMAL
, fullPath
, NULL
, NULL
, kServiceDependencies
,
530 err
= translate_errno( service
, (OSStatus
) GetLastError(), kDuplicateErr
);
531 require_noerr( err
, exit
);
533 err
= SetServiceParameters();
538 err
= SetServiceInfo( scm
, inName
, inDescription
);
542 ok
= StartService( service
, 0, NULL
);
543 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kInUseErr
);
544 require_noerr( err
, exit
);
546 ReportStatus( EVENTLOG_SUCCESS
, "installed service \"%s\"/\"%s\" at \"%s\"\n", inName
, inDisplayName
, inPath
);
552 CloseServiceHandle( service
);
556 CloseServiceHandle( scm
);
561 //===========================================================================================================================
563 //===========================================================================================================================
565 static OSStatus
RemoveService( LPCTSTR inName
)
571 SERVICE_STATUS status
;
576 // Open a connection to the service.
578 scm
= OpenSCManager( 0, 0, SC_MANAGER_ALL_ACCESS
);
579 err
= translate_errno( scm
, (OSStatus
) GetLastError(), kOpenErr
);
580 require_noerr( err
, exit
);
582 service
= OpenService( scm
, inName
, SERVICE_STOP
| SERVICE_QUERY_STATUS
| DELETE
);
583 err
= translate_errno( service
, (OSStatus
) GetLastError(), kNotFoundErr
);
584 require_noerr( err
, exit
);
586 // Stop the service, if it is not already stopped, then delete it.
588 ok
= QueryServiceStatus( service
, &status
);
589 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kAuthenticationErr
);
590 require_noerr( err
, exit
);
592 if( status
.dwCurrentState
!= SERVICE_STOPPED
)
594 ok
= ControlService( service
, SERVICE_CONTROL_STOP
, &status
);
595 check_translated_errno( ok
, (OSStatus
) GetLastError(), kAuthenticationErr
);
598 ok
= DeleteService( service
);
599 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kDeletedErr
);
600 require_noerr( err
, exit
);
602 ReportStatus( EVENTLOG_SUCCESS
, "Removed service \"%s\"\n", inName
);
608 CloseServiceHandle( service
);
612 CloseServiceHandle( scm
);
619 //===========================================================================================================================
620 // SetServiceParameters
621 //===========================================================================================================================
623 static OSStatus
SetServiceParameters()
626 DWORD valueLen
= sizeof(DWORD
);
634 // Add/Open Parameters section under service entry in registry
636 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
, &key
);
637 require_noerr( err
, exit
);
640 // If the value isn't already there, then we create it
642 err
= RegQueryValueEx(key
, kServiceManageLLRouting
, 0, &type
, (LPBYTE
) &value
, &valueLen
);
644 if (err
!= ERROR_SUCCESS
)
648 err
= RegSetValueEx( key
, kServiceManageLLRouting
, 0, REG_DWORD
, (const LPBYTE
) &value
, sizeof(DWORD
) );
649 require_noerr( err
, exit
);
664 //===========================================================================================================================
665 // GetServiceParameters
666 //===========================================================================================================================
668 static OSStatus
GetServiceParameters()
679 // Add/Open Parameters section under service entry in registry
681 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
, &key
);
682 require_noerr( err
, exit
);
684 valueLen
= sizeof(DWORD
);
685 err
= RegQueryValueEx(key
, kServiceManageLLRouting
, 0, &type
, (LPBYTE
) &value
, &valueLen
);
686 if (err
== ERROR_SUCCESS
)
688 gServiceManageLLRouting
= (value
) ? true : false;
691 valueLen
= sizeof(DWORD
);
692 err
= RegQueryValueEx(key
, kServiceCacheEntryCount
, 0, &type
, (LPBYTE
) &value
, &valueLen
);
693 if (err
== ERROR_SUCCESS
)
695 gServiceCacheEntryCount
= value
;
709 //===========================================================================================================================
711 //===========================================================================================================================
713 static OSStatus
CheckFirewall()
718 ENUM_SERVICE_STATUS
* lpService
= NULL
;
722 DWORD bytesNeeded
= 0;
724 DWORD resumeHandle
= 0;
729 BOOL isRunning
= FALSE
;
730 OSStatus err
= kUnknownErr
;
732 // Check to see if the firewall service is running. If it isn't, then
733 // we want to return immediately
735 sc
= OpenSCManager( NULL
, NULL
, SC_MANAGER_ENUMERATE_SERVICE
);
736 err
= translate_errno( sc
, GetLastError(), kUnknownErr
);
737 require_noerr( err
, exit
);
739 srvType
= SERVICE_WIN32
;
740 srvState
= SERVICE_STATE_ALL
;
744 // Call EnumServicesStatus using the handle returned by OpenSCManager
746 ok
= EnumServicesStatus ( sc
, srvType
, srvState
, lpService
, dwBytes
, &bytesNeeded
, &srvCount
, &resumeHandle
);
748 if ( ok
|| ( GetLastError() != ERROR_MORE_DATA
) )
758 dwBytes
= bytesNeeded
;
760 lpService
= ( ENUM_SERVICE_STATUS
* ) malloc( dwBytes
);
761 require_action( lpService
, exit
, err
= mStatus_NoMemoryErr
);
764 err
= translate_errno( ok
, GetLastError(), kUnknownErr
);
765 require_noerr( err
, exit
);
767 for ( i
= 0; i
< srvCount
; i
++ )
769 if ( wcscmp( lpService
[i
].lpServiceName
, L
"SharedAccess" ) == 0 )
771 if ( lpService
[i
].ServiceStatus
.dwCurrentState
== SERVICE_RUNNING
)
780 require_action( isRunning
, exit
, err
= kUnknownErr
);
782 // Check to see if we've managed the firewall.
783 // This package might have been installed, then
784 // the OS was upgraded to SP2 or above. If that's
785 // the case, then we need to manipulate the firewall
786 // so networking works correctly.
788 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
, &key
);
789 require_noerr( err
, exit
);
791 valueLen
= sizeof(DWORD
);
792 err
= RegQueryValueEx(key
, kServiceManageFirewall
, 0, &type
, (LPBYTE
) &value
, &valueLen
);
794 if ((err
!= ERROR_SUCCESS
) || (value
== 0))
796 wchar_t fullPath
[ MAX_PATH
];
799 // Get a full path to the executable
801 size
= GetModuleFileNameW( NULL
, fullPath
, sizeof( fullPath
) );
802 err
= translate_errno( size
> 0, (OSStatus
) GetLastError(), kPathErr
);
803 require_noerr( err
, exit
);
805 err
= mDNSAddToFirewall(fullPath
, kServiceFirewallName
);
806 require_noerr( err
, exit
);
809 err
= RegSetValueEx( key
, kServiceManageFirewall
, 0, REG_DWORD
, (const LPBYTE
) &value
, sizeof( DWORD
) );
810 require_noerr( err
, exit
);
827 CloseServiceHandle ( sc
);
835 //===========================================================================================================================
837 //===========================================================================================================================
839 static OSStatus
SetServiceInfo( SC_HANDLE inSCM
, LPCTSTR inServiceName
, LPCTSTR inDescription
)
844 SERVICE_DESCRIPTION description
;
845 SERVICE_FAILURE_ACTIONS actions
;
849 check( inServiceName
);
850 check( inDescription
);
855 // Open the database (if not provided) and lock it to prevent other access while re-configuring.
859 inSCM
= OpenSCManager( NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
860 err
= translate_errno( inSCM
, (OSStatus
) GetLastError(), kOpenErr
);
861 require_noerr( err
, exit
);
864 lock
= LockServiceDatabase( inSCM
);
865 err
= translate_errno( lock
, (OSStatus
) GetLastError(), kInUseErr
);
866 require_noerr( err
, exit
);
868 // Open a handle to the service.
870 service
= OpenService( inSCM
, inServiceName
, SERVICE_CHANGE_CONFIG
|SERVICE_START
);
871 err
= translate_errno( service
, (OSStatus
) GetLastError(), kNotFoundErr
);
872 require_noerr( err
, exit
);
874 // Change the description.
876 description
.lpDescription
= (LPTSTR
) inDescription
;
877 ok
= ChangeServiceConfig2( service
, SERVICE_CONFIG_DESCRIPTION
, &description
);
878 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kParamErr
);
879 require_noerr( err
, exit
);
881 actions
.dwResetPeriod
= INFINITE
;
882 actions
.lpRebootMsg
= NULL
;
883 actions
.lpCommand
= NULL
;
884 actions
.cActions
= 1;
885 actions
.lpsaActions
= &action
;
887 action
.Type
= SC_ACTION_RESTART
;
889 ok
= ChangeServiceConfig2( service
, SERVICE_CONFIG_FAILURE_ACTIONS
, &actions
);
890 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kParamErr
);
891 require_noerr( err
, exit
);
896 // Close the service and release the lock.
900 CloseServiceHandle( service
);
904 UnlockServiceDatabase( lock
);
909 //===========================================================================================================================
911 //===========================================================================================================================
913 static void ReportStatus( int inType
, const char *inFormat
, ... )
915 if( !gServiceQuietMode
)
919 va_start( args
, inFormat
);
920 if( gServiceEventSource
)
924 const char * array
[ 1 ];
926 vsprintf( s
, inFormat
, args
);
928 ok
= ReportEventA( gServiceEventSource
, (WORD
) inType
, 0, 0x20000001L
, NULL
, 1, 0, array
, NULL
);
929 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
935 n
= vfprintf( stderr
, inFormat
, args
);
942 //===========================================================================================================================
944 //===========================================================================================================================
946 static OSStatus
RunDirect( int argc
, LPTSTR argv
[] )
954 // Install a Console Control Handler to handle things like control-c signals.
956 ok
= SetConsoleCtrlHandler( ConsoleControlHandler
, TRUE
);
957 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
958 require_noerr( err
, exit
);
960 err
= ServiceSpecificInitialize( argc
, argv
);
961 require_noerr( err
, exit
);
964 // Run the service. This does not return until the service quits or is stopped.
966 ReportStatus( EVENTLOG_SUCCESS
, "Running \"%s\" service directly\n", kServiceName
);
968 err
= ServiceSpecificRun( argc
, argv
);
969 require_noerr( err
, exit
);
976 ServiceSpecificFinalize( argc
, argv
);
985 //===========================================================================================================================
987 //===========================================================================================================================
989 static void WINAPI
ServiceMain( DWORD argc
, LPTSTR argv
[] )
994 err
= ServiceSetupEventLogging();
997 err
= GetServiceParameters();
1000 // Initialize the service status and register the service control handler with the name of the service.
1002 gServiceStatus
.dwServiceType
= SERVICE_WIN32_SHARE_PROCESS
;
1003 gServiceStatus
.dwCurrentState
= 0;
1004 gServiceStatus
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
|SERVICE_ACCEPT_POWEREVENT
;
1005 gServiceStatus
.dwWin32ExitCode
= NO_ERROR
;
1006 gServiceStatus
.dwServiceSpecificExitCode
= NO_ERROR
;
1007 gServiceStatus
.dwCheckPoint
= 0;
1008 gServiceStatus
.dwWaitHint
= 0;
1010 gServiceStatusHandle
= RegisterServiceCtrlHandlerEx( argv
[ 0 ], ServiceControlHandler
, NULL
);
1011 err
= translate_errno( gServiceStatusHandle
, (OSStatus
) GetLastError(), kInUseErr
);
1012 require_noerr( err
, exit
);
1014 // Mark the service as starting.
1016 gServiceStatus
.dwCurrentState
= SERVICE_START_PENDING
;
1017 gServiceStatus
.dwCheckPoint
= 0;
1018 gServiceStatus
.dwWaitHint
= 5000; // 5 seconds
1019 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
1020 check_translated_errno( ok
, GetLastError(), kParamErr
);
1022 // Run the service. This does not return until the service quits or is stopped.
1024 err
= ServiceRun( (int) argc
, argv
);
1027 gServiceStatus
.dwWin32ExitCode
= ERROR_SERVICE_SPECIFIC_ERROR
;
1028 gServiceStatus
.dwServiceSpecificExitCode
= (DWORD
) err
;
1031 // Service-specific work is done so mark the service as stopped.
1033 gServiceStatus
.dwCurrentState
= SERVICE_STOPPED
;
1034 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
1035 check_translated_errno( ok
, GetLastError(), kParamErr
);
1037 // Note: The service status handle should not be closed according to Microsoft documentation.
1040 if( gServiceEventSource
)
1042 ok
= DeregisterEventSource( gServiceEventSource
);
1043 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
1044 gServiceEventSource
= NULL
;
1048 //===========================================================================================================================
1049 // ServiceSetupEventLogging
1050 //===========================================================================================================================
1052 static OSStatus
ServiceSetupEventLogging( void )
1057 DWORD typesSupported
;
1058 TCHAR path
[ MAX_PATH
];
1063 // Add/Open source name as a sub-key under the Application key in the EventLog registry key.
1065 s
= TEXT("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\") kServiceName
;
1066 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, s
, &key
);
1067 require_noerr( err
, exit
);
1069 // Add the name to the EventMessageFile subkey.
1072 GetModuleFileName( NULL
, path
, MAX_PATH
);
1073 n
= (DWORD
) ( ( StrLen( path
) + 1 ) * sizeof( TCHAR
) );
1074 err
= RegSetValueEx( key
, TEXT("EventMessageFile"), 0, REG_EXPAND_SZ
, (const LPBYTE
) path
, n
);
1075 require_noerr( err
, exit
);
1077 // Set the supported event types in the TypesSupported subkey.
1081 | EVENTLOG_ERROR_TYPE
1082 | EVENTLOG_WARNING_TYPE
1083 | EVENTLOG_INFORMATION_TYPE
1084 | EVENTLOG_AUDIT_SUCCESS
1085 | EVENTLOG_AUDIT_FAILURE
;
1086 err
= RegSetValueEx( key
, TEXT("TypesSupported"), 0, REG_DWORD
, (const LPBYTE
) &typesSupported
, sizeof( DWORD
) );
1087 require_noerr( err
, exit
);
1089 // Set up the event source.
1091 gServiceEventSource
= RegisterEventSource( NULL
, kServiceName
);
1092 err
= translate_errno( gServiceEventSource
, (OSStatus
) GetLastError(), kParamErr
);
1093 require_noerr( err
, exit
);
1103 //===========================================================================================================================
1104 // ServiceControlHandler
1105 //===========================================================================================================================
1107 static DWORD WINAPI
ServiceControlHandler( DWORD inControl
, DWORD inEventType
, LPVOID inEventData
, LPVOID inContext
)
1112 DEBUG_UNUSED( inEventData
);
1113 DEBUG_UNUSED( inContext
);
1118 case SERVICE_CONTROL_STOP
:
1119 dlog( kDebugLevelNotice
, DEBUG_NAME
"ServiceControlHandler: SERVICE_CONTROL_STOP\n" );
1125 case SERVICE_CONTROL_POWEREVENT
:
1127 if (inEventType
== PBT_APMSUSPEND
)
1129 mDNSCoreMachineSleep(&gMDNSRecord
, TRUE
);
1131 else if (inEventType
== PBT_APMRESUMESUSPEND
)
1133 mDNSCoreMachineSleep(&gMDNSRecord
, FALSE
);
1139 dlog( kDebugLevelNotice
, DEBUG_NAME
"ServiceControlHandler: event (0x%08X)\n", inControl
);
1143 if( setStatus
&& gServiceStatusHandle
)
1145 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
1146 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
1152 //===========================================================================================================================
1154 //===========================================================================================================================
1156 static OSStatus
ServiceRun( int argc
, LPTSTR argv
[] )
1162 DEBUG_UNUSED( argc
);
1163 DEBUG_UNUSED( argv
);
1165 initialized
= FALSE
;
1167 // Initialize the service-specific stuff and mark the service as running.
1169 err
= ServiceSpecificInitialize( argc
, argv
);
1170 require_noerr( err
, exit
);
1173 gServiceStatus
.dwCurrentState
= SERVICE_RUNNING
;
1174 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
1175 check_translated_errno( ok
, GetLastError(), kParamErr
);
1177 err
= CheckFirewall();
1182 gRetryFirewall
= TRUE
;
1185 // Run the service-specific stuff. This does not return until the service quits or is stopped.
1187 ReportStatus( EVENTLOG_INFORMATION_TYPE
, "mDNSResponder started\n" );
1188 err
= ServiceSpecificRun( argc
, argv
);
1189 ReportStatus( EVENTLOG_INFORMATION_TYPE
, "mDNSResponder stopped (%d)\n", err
);
1190 require_noerr( err
, exit
);
1192 // Service stopped. Clean up and we're done.
1197 ServiceSpecificFinalize( argc
, argv
);
1202 //===========================================================================================================================
1204 //===========================================================================================================================
1206 static void ServiceStop( void )
1211 // Signal the event to cause the service to exit.
1213 if( gServiceStatusHandle
)
1215 gServiceStatus
.dwCurrentState
= SERVICE_STOP_PENDING
;
1216 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
1217 check_translated_errno( ok
, GetLastError(), kParamErr
);
1220 err
= ServiceSpecificStop();
1226 #pragma mark == Service Specific ==
1229 //===========================================================================================================================
1230 // ServiceSpecificInitialize
1231 //===========================================================================================================================
1233 static OSStatus
ServiceSpecificInitialize( int argc
, LPTSTR argv
[] )
1237 DEBUG_UNUSED( argc
);
1238 DEBUG_UNUSED( argv
);
1240 memset( &gMDNSRecord
, 0, sizeof gMDNSRecord
);
1241 memset( &gPlatformStorage
, 0, sizeof gPlatformStorage
);
1243 gPlatformStorage
.idleThreadCallback
= udsIdle
;
1244 gPlatformStorage
.hostDescriptionChangedCallback
= HostDescriptionChanged
;
1246 InitializeCriticalSection(&gEventSourceLock
);
1248 gStopEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1249 err
= translate_errno( gStopEvent
, errno_compat(), kNoResourcesErr
);
1250 require_noerr( err
, exit
);
1252 err
= mDNS_Init( &gMDNSRecord
, &gPlatformStorage
, gRRCache
, RR_CACHE_SIZE
, mDNS_Init_AdvertiseLocalAddresses
, CoreCallback
, mDNS_Init_NoInitCallbackContext
);
1253 require_noerr( err
, exit
);
1255 err
= udsserver_init(dnssd_InvalidSocket
);
1256 require_noerr( err
, exit
);
1259 // <rdar://problem/4096464> Don't call SetLLRoute on loopback
1261 // Otherwise, set a route to link local addresses (169.254.0.0)
1264 if ( gServiceManageLLRouting
&& !gPlatformStorage
.registeredLoopback4
)
1266 SetLLRoute( &gMDNSRecord
);
1272 ServiceSpecificFinalize( argc
, argv
);
1277 //===========================================================================================================================
1278 // ServiceSpecificRun
1279 //===========================================================================================================================
1281 static OSStatus
ServiceSpecificRun( int argc
, LPTSTR argv
[] )
1286 DEBUG_UNUSED( argc
);
1287 DEBUG_UNUSED( argv
);
1289 // Main event loop. Process connection requests and state changes (i.e. quit).
1291 timeout
= ( gRetryFirewall
) ? kRetryFirewallPeriod
: INFINITE
;
1293 while( (result
= WaitForSingleObject( gStopEvent
, timeout
) ) != WAIT_OBJECT_0
)
1295 if ( result
== WAIT_TIMEOUT
)
1299 err
= CheckFirewall();
1306 // Unexpected wait result.
1307 dlog( kDebugLevelWarning
, DEBUG_NAME
"%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__
, result
);
1314 //===========================================================================================================================
1315 // ServiceSpecificStop
1316 //===========================================================================================================================
1318 static OSStatus
ServiceSpecificStop( void )
1323 ok
= SetEvent(gStopEvent
);
1324 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
1325 require_noerr( err
, exit
);
1330 //===========================================================================================================================
1331 // ServiceSpecificFinalize
1332 //===========================================================================================================================
1334 static void ServiceSpecificFinalize( int argc
, LPTSTR argv
[] )
1336 DEBUG_UNUSED( argc
);
1337 DEBUG_UNUSED( argv
);
1340 // clean up any open sessions
1342 while (gEventSources
.Head
)
1344 EventSourceFinalize((Win32EventSource
*) gEventSources
.Head
);
1347 // give a chance for the udsserver code to clean up
1349 udsserver_exit(dnssd_InvalidSocket
);
1352 // and finally close down the mDNSCore
1354 mDNS_Close(&gMDNSRecord
);
1357 // clean up the event sources mutex...no one should be using it now
1359 DeleteCriticalSection(&gEventSourceLock
);
1364 CoreCallback(mDNS
* const inMDNS
, mStatus status
)
1366 if (status
== mStatus_ConfigChanged
)
1369 // <rdar://problem/4096464> Don't call SetLLRoute on loopback
1371 // Otherwise, set a route to link local addresses (169.254.0.0)
1374 if ( gServiceManageLLRouting
&& !inMDNS
->p
->registeredLoopback4
)
1376 SetLLRoute( inMDNS
);
1383 udsIdle(mDNS
* const inMDNS
, mDNSs32 interval
)
1385 DEBUG_UNUSED( inMDNS
);
1388 // rdar://problem/3697326
1390 // udsserver_idle wasn't being locked. This resulted
1391 // in multiple threads contesting for the all_requests
1392 // data structure in uds_daemon.c
1394 mDNSPlatformLock(&gMDNSRecord
);
1396 interval
= udsserver_idle(interval
);
1398 mDNSPlatformUnlock(&gMDNSRecord
);
1405 HostDescriptionChanged(mDNS
* const inMDNS
)
1407 DEBUG_UNUSED( inMDNS
);
1409 udsserver_handle_configchange(inMDNS
);
1413 mDNSlocal
unsigned WINAPI
1414 udsSocketThread(LPVOID inParam
)
1416 Win32EventSource
* source
= (Win32EventSource
*) inParam
;
1417 DWORD threadID
= GetCurrentThreadId();
1422 bool locked
= false;
1425 waitCount
= source
->waitCount
;
1426 waitList
[0] = source
->waitList
[0];
1427 waitList
[1] = source
->waitList
[1];
1428 done
= (bool) (source
->flags
& EventSourceFinalized
);
1434 result
= WaitForMultipleObjects(waitCount
, waitList
, FALSE
, INFINITE
);
1436 mDNSPlatformLock(&gMDNSRecord
);
1439 // <rdar://problem/3838237>
1441 // Look up the source by the thread id. This will ensure that the
1442 // source is still extant. It could already have been deleted
1443 // by the processing thread.
1448 for (source
= gEventSources
.Head
; source
; source
= source
->next
)
1450 if (source
->threadID
== threadID
)
1456 EventSourceUnlock();
1466 if (result
== WAIT_OBJECT_0
)
1468 source
->callback(source
->context
);
1473 else if (result
== WAIT_OBJECT_0
+ 1)
1476 // this is a bit of a hack. we want to clean up the internal data structures
1477 // so we'll go in here and it will clean up for us
1479 shutdown(source
->sock
, 2);
1480 source
->callback(source
->context
);
1486 // Unexpected wait result.
1487 dlog( kDebugLevelWarning
, DEBUG_NAME
"%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__
, result
);
1491 done
= (bool) (source
->flags
& EventSourceFinalized
);
1493 mDNSPlatformUnlock(&gMDNSRecord
);
1498 source
->flags
|= EventSourceFlagsThreadDone
;
1499 safeToClose
= !( source
->flags
& EventSourceFlagsNoClose
);
1500 EventSourceUnlock();
1504 EventSourceFinalize( source
);
1511 mDNSPlatformUnlock(&gMDNSRecord
);
1514 _endthreadex_compat( (unsigned) err
);
1515 return( (unsigned) err
);
1520 udsSupportAddFDToEventLoop( SocketRef fd
, udsEventCallback callback
, void *context
)
1522 Win32EventSource
* newSource
;
1526 newSource
= malloc(sizeof(Win32EventSource
));
1527 require_action( newSource
, exit
, err
= mStatus_NoMemoryErr
);
1528 memset(newSource
, 0, sizeof(Win32EventSource
));
1530 newSource
->flags
= 0;
1531 newSource
->sock
= (SOCKET
) fd
;
1532 newSource
->callback
= callback
;
1533 newSource
->context
= context
;
1535 newSource
->socketEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1536 err
= translate_errno( newSource
->socketEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1537 require_noerr( err
, exit
);
1539 newSource
->closeEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1540 err
= translate_errno( newSource
->closeEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1541 require_noerr( err
, exit
);
1543 err
= WSAEventSelect(newSource
->sock
, newSource
->socketEvent
, FD_ACCEPT
|FD_READ
|FD_CLOSE
);
1544 err
= translate_errno( err
== 0, errno_compat(), kNoResourcesErr
);
1545 require_noerr( err
, exit
);
1547 newSource
->waitCount
= 0;
1548 newSource
->waitList
[ newSource
->waitCount
++ ] = newSource
->socketEvent
;
1549 newSource
->waitList
[ newSource
->waitCount
++ ] = newSource
->closeEvent
;
1556 // add the event source to the end of the list, while checking
1557 // to see if the list needs to be initialized
1559 if ( gEventSources
.LinkOffset
== 0)
1561 InitLinkedList( &gEventSources
, offsetof( Win32EventSource
, next
));
1564 AddToTail( &gEventSources
, newSource
);
1567 // no longer using the list
1569 EventSourceUnlock();
1571 // Create thread with _beginthreadex() instead of CreateThread() to avoid memory leaks when using static run-time
1572 // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
1573 // Create the thread suspended then resume it so the thread handle and ID are valid before the thread starts running.
1574 newSource
->threadHandle
= (HANDLE
) _beginthreadex_compat( NULL
, 0, udsSocketThread
, newSource
, CREATE_SUSPENDED
, &newSource
->threadID
);
1575 err
= translate_errno( newSource
->threadHandle
, (mStatus
) GetLastError(), kUnknownErr
);
1576 require_noerr( err
, exit
);
1578 result
= ResumeThread( newSource
->threadHandle
);
1579 err
= translate_errno( result
!= (DWORD
) -1, errno_compat(), kNoResourcesErr
);
1580 require_noerr( err
, exit
);
1584 if (err
&& newSource
)
1586 EventSourceFinalize(newSource
);
1594 udsSupportRemoveFDFromEventLoop( SocketRef fd
) // Note: This also CLOSES the socket
1596 Win32EventSource
* source
;
1597 mStatus err
= mStatus_NoError
;
1600 // find the event source
1604 for (source
= gEventSources
.Head
; source
; source
= source
->next
)
1606 if (source
->sock
== (SOCKET
) fd
)
1613 // if we found him, finalize him
1617 EventSourceFinalize(source
);
1621 // done with the list
1623 EventSourceUnlock();
1631 mDNSexport
void RecordUpdatedNiceLabel(mDNS
*const m
, mDNSs32 delay
)
1640 EventSourceFinalize(Win32EventSource
* source
)
1644 Win32EventSource
* inserted
;
1653 // Find the session in the list.
1658 for( inserted
= (Win32EventSource
*) gEventSources
.Head
; inserted
; inserted
= inserted
->next
)
1660 if( inserted
== source
)
1665 require_action( inserted
, exit
, err
= kNotFoundErr
);
1668 // note that we've had finalize called
1670 source
->flags
|= EventSourceFinalized
;
1672 // If we're being called from the same thread as the session (e.g. message callback is closing the session) then
1673 // we must defer the close until the thread is done because the thread is still using the session object.
1676 threadID
= GetCurrentThreadId();
1677 sameThread
= source
->threadHandle
&& ( threadID
== source
->threadID
);
1678 if( sameThread
&& !( source
->flags
& EventSourceFlagsThreadDone
) )
1680 source
->flags
&= ~EventSourceFlagsNoClose
;
1684 // If the thread we're not being called from the session thread, but the thread has already marked itself as
1685 // as done (e.g. session closed from something like a peer disconnect and at the same time the client also
1686 // tried to close) then we only want to continue with the close if the thread is not going to close itself.
1688 if( !sameThread
&& ( source
->flags
& EventSourceFlagsThreadDone
) && !( source
->flags
& EventSourceFlagsNoClose
) )
1693 // Signal a close so the thread exits.
1695 if( source
->closeEvent
)
1697 ok
= SetEvent( source
->closeEvent
);
1698 check_translated_errno( ok
, errno_compat(), kUnknownErr
);
1706 source
->flags
|= EventSourceFlagsNoClose
;
1708 // Remove the session from the list.
1709 RemoveFromList(&gEventSources
, source
);
1711 EventSourceUnlock();
1714 // Wait for the thread to exit. Give up after 3 seconds to handle a hung thread.
1716 if( source
->threadHandle
&& ( threadID
!= source
->threadID
) )
1718 result
= WaitForSingleObject( source
->threadHandle
, 3 * 1000 );
1719 check_translated_errno( result
== WAIT_OBJECT_0
, (OSStatus
) GetLastError(), result
);
1722 // Release the thread.
1724 if( source
->threadHandle
)
1726 ok
= CloseHandle( source
->threadHandle
);
1727 check_translated_errno( ok
, errno_compat(), kUnknownErr
);
1728 source
->threadHandle
= NULL
;
1731 // Release the socket event.
1733 if( source
->socketEvent
)
1735 ok
= CloseHandle( source
->socketEvent
);
1736 check_translated_errno( ok
, errno_compat(), kUnknownErr
);
1737 source
->socketEvent
= NULL
;
1740 // Release the close event.
1742 if( source
->closeEvent
)
1744 ok
= CloseHandle( source
->closeEvent
);
1745 check_translated_errno( ok
, errno_compat(), kUnknownErr
);
1746 source
->closeEvent
= NULL
;
1749 // Release the memory used by the object.
1754 dlog( kDebugLevelNotice
, DEBUG_NAME
"session closed\n" );
1760 EventSourceUnlock();
1770 EnterCriticalSection(&gEventSourceLock
);
1777 LeaveCriticalSection(&gEventSourceLock
);
1781 //===========================================================================================================================
1783 //===========================================================================================================================
1786 HaveRoute( PMIB_IPFORWARDROW rowExtant
, unsigned long addr
)
1788 PMIB_IPFORWARDTABLE pIpForwardTable
= NULL
;
1790 BOOL bOrder
= FALSE
;
1793 unsigned long int i
;
1796 // Find out how big our buffer needs to be.
1798 err
= GetIpForwardTable(NULL
, &dwSize
, bOrder
);
1799 require_action( err
== ERROR_INSUFFICIENT_BUFFER
, exit
, err
= kUnknownErr
);
1802 // Allocate the memory for the table
1804 pIpForwardTable
= (PMIB_IPFORWARDTABLE
) malloc( dwSize
);
1805 require_action( pIpForwardTable
, exit
, err
= kNoMemoryErr
);
1808 // Now get the table.
1810 err
= GetIpForwardTable(pIpForwardTable
, &dwSize
, bOrder
);
1811 require_noerr( err
, exit
);
1814 // Search for the row in the table we want.
1816 for ( i
= 0; i
< pIpForwardTable
->dwNumEntries
; i
++)
1818 if ( pIpForwardTable
->table
[i
].dwForwardDest
== addr
)
1820 memcpy( rowExtant
, &(pIpForwardTable
->table
[i
]), sizeof(*rowExtant
) );
1828 if ( pIpForwardTable
!= NULL
)
1830 free(pIpForwardTable
);
1837 //===========================================================================================================================
1839 //===========================================================================================================================
1842 IsValidAddress( const char * addr
)
1844 return ( addr
&& ( strcmp( addr
, "0.0.0.0" ) != 0 ) ) ? true : false;
1848 //===========================================================================================================================
1850 //===========================================================================================================================
1853 SetLLRoute( mDNS
* const inMDNS
)
1856 MIB_IPFORWARDROW rowExtant
;
1858 MIB_IPFORWARDROW row
;
1861 ZeroMemory(&row
, sizeof(row
));
1863 err
= GetRouteDestination(&ifIndex
, &row
.dwForwardNextHop
);
1864 require_noerr( err
, exit
);
1865 row
.dwForwardDest
= inet_addr(kLLNetworkAddr
);
1866 row
.dwForwardIfIndex
= ifIndex
;
1867 row
.dwForwardMask
= inet_addr(kLLNetworkAddrMask
);
1868 row
.dwForwardType
= 3;
1869 row
.dwForwardProto
= MIB_IPPROTO_NETMGMT
;
1870 row
.dwForwardAge
= 0;
1871 row
.dwForwardPolicy
= 0;
1872 row
.dwForwardMetric1
= 30;
1873 row
.dwForwardMetric2
= (DWORD
) - 1;
1874 row
.dwForwardMetric3
= (DWORD
) - 1;
1875 row
.dwForwardMetric4
= (DWORD
) - 1;
1876 row
.dwForwardMetric5
= (DWORD
) - 1;
1881 // check to make sure we don't already have a route
1883 if ( HaveRoute( &rowExtant
, inet_addr( kLLNetworkAddr
) ) )
1886 // set the age to 0 so that we can do a memcmp.
1888 rowExtant
.dwForwardAge
= 0;
1891 // check to see if this route is the same as our route
1893 if (memcmp(&row
, &rowExtant
, sizeof(row
)) != 0)
1896 // if it isn't then delete this entry
1898 DeleteIpForwardEntry(&rowExtant
);
1903 // else it is, so we don't want to create another route
1909 if (addRoute
&& row
.dwForwardNextHop
)
1911 err
= CreateIpForwardEntry(&row
);
1913 require_noerr( err
, exit
);
1917 // Now we want to see if we should install a default route for this interface.
1918 // We want to do this if the following are true:
1920 // 1. This interface has a link-local address
1921 // 2. This is the only IPv4 interface
1924 if ( ( row
.dwForwardNextHop
& 0xFFFF ) == row
.dwForwardDest
)
1926 mDNSInterfaceData
* ifd
;
1927 int numLinkLocalInterfaces
= 0;
1928 int numInterfaces
= 0;
1930 for ( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
1932 if ( ifd
->defaultAddr
.type
== mDNSAddrType_IPv4
)
1936 if ( ( ifd
->interfaceInfo
.ip
.ip
.v4
.b
[0] == 169 ) && ( ifd
->interfaceInfo
.ip
.ip
.v4
.b
[1] == 254 ) )
1938 numLinkLocalInterfaces
++;
1943 row
.dwForwardDest
= 0;
1944 row
.dwForwardIfIndex
= ifIndex
;
1945 row
.dwForwardMask
= 0;
1946 row
.dwForwardType
= 3;
1947 row
.dwForwardProto
= MIB_IPPROTO_NETMGMT
;
1948 row
.dwForwardAge
= 0;
1949 row
.dwForwardPolicy
= 0;
1950 row
.dwForwardMetric1
= 20;
1951 row
.dwForwardMetric2
= (DWORD
) - 1;
1952 row
.dwForwardMetric3
= (DWORD
) - 1;
1953 row
.dwForwardMetric4
= (DWORD
) - 1;
1954 row
.dwForwardMetric5
= (DWORD
) - 1;
1956 if ( numInterfaces
== numLinkLocalInterfaces
)
1958 if ( !HaveRoute( &row
, 0 ) )
1960 err
= CreateIpForwardEntry(&row
);
1961 require_noerr( err
, exit
);
1966 DeleteIpForwardEntry( &row
);
1976 //===========================================================================================================================
1977 // GetRouteDestination
1978 //===========================================================================================================================
1981 GetRouteDestination(DWORD
* ifIndex
, DWORD
* address
)
1984 IP_ADAPTER_INFO
* pAdapterInfo
= NULL
;
1985 IP_ADAPTER_INFO
* pAdapter
= NULL
;
1987 mDNSBool done
= mDNSfalse
;
1991 // GetBestInterface will fail if there is no default gateway
1992 // configured. If that happens, we will just take the first
1993 // interface in the list. MSDN support says there is no surefire
1994 // way to manually determine what the best interface might
1995 // be for a particular network address.
1997 ia
.s_addr
= inet_addr(kLLNetworkAddr
);
1998 err
= GetBestInterface(*(IPAddr
*) &ia
, ifIndex
);
2006 // Make an initial call to GetAdaptersInfo to get
2007 // the necessary size into the bufLen variable
2009 err
= GetAdaptersInfo( NULL
, &bufLen
);
2010 require_action( err
== ERROR_BUFFER_OVERFLOW
, exit
, err
= kUnknownErr
);
2012 pAdapterInfo
= (IP_ADAPTER_INFO
*) malloc( bufLen
);
2013 require_action( pAdapterInfo
, exit
, err
= kNoMemoryErr
);
2015 err
= GetAdaptersInfo( pAdapterInfo
, &bufLen
);
2016 require_noerr( err
, exit
);
2018 pAdapter
= pAdapterInfo
;
2021 // <rdar://problem/3718122>
2023 // Look for the Nortel VPN virtual interface. This interface
2024 // is identified by it's unique MAC address: 44-45-53-54-42-00
2026 // If the interface is active (i.e., has a non-zero IP Address),
2027 // then we want to disable routing table modifications.
2031 if ((pAdapter
->Type
== MIB_IF_TYPE_ETHERNET
) &&
2032 (pAdapter
->AddressLength
== 6) &&
2033 (pAdapter
->Address
[0] == 0x44) &&
2034 (pAdapter
->Address
[1] == 0x45) &&
2035 (pAdapter
->Address
[2] == 0x53) &&
2036 (pAdapter
->Address
[3] == 0x54) &&
2037 (pAdapter
->Address
[4] == 0x42) &&
2038 (pAdapter
->Address
[5] == 0x00) &&
2039 (inet_addr( pAdapter
->IpAddressList
.IpAddress
.String
) != 0))
2044 pAdapter
= pAdapter
->Next
;
2049 pAdapter
= pAdapterInfo
;
2054 // If we don't have an interface selected, choose the first one that is of type ethernet and
2055 // has a valid IP Address
2057 if ((pAdapter
->Type
== MIB_IF_TYPE_ETHERNET
) && ( IsValidAddress( pAdapter
->IpAddressList
.IpAddress
.String
) ) && (!(*ifIndex
) || (pAdapter
->Index
== (*ifIndex
))))
2059 *address
= inet_addr( pAdapter
->IpAddressList
.IpAddress
.String
);
2060 *ifIndex
= pAdapter
->Index
;
2065 pAdapter
= pAdapter
->Next
;
2068 // If we found the right interface, or we weren't trying to find a specific interface then we're done
2070 if ( !err
|| !( *ifIndex
) )
2075 // Otherwise, try again by wildcarding the interface
2085 if ( pAdapterInfo
!= NULL
)
2087 free( pAdapterInfo
);