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.46 2009/06/05 18:28:24 herscher
21 <rdar://problem/6125087> mDNSResponder should be able to identify VPN adapters generically
22 <rdar://problem/6885843> WIN7: Bonjour removes the default gateway entry and thereby breaks network connectivity
24 Revision 1.45 2009/04/30 20:07:51 mcguire
25 <rdar://problem/6822674> Support multiple UDSs from launchd
27 Revision 1.44 2009/03/30 20:41:36 herscher
28 <rdar://problem/5925472> Current Bonjour code does not compile on Windows
29 <rdar://problem/6330821> Bonjour for Windows incompatible w/Juniper Network Connect. Do a substring search for "Juniper" in the description field
30 of the network adapter.
31 <rdar://problem/6122028> Bonjour for Windows incompatible w/Cisco AnyConnect VPN Client
32 <rdar://problem/5652098> Bonjour for Windows incompatible w/Juniper Network Connect. Update the adapter name per info received from Juniper
33 <rdar://problem/5781566> Core: Default Gateway set to 0.0.0.0 on Vista causes ARP flood
34 <rdar://problem/5991983> Change the registry values from Apple Computer, Inc. to Apple Inc.
35 <rdar://problem/5301328> wchar/sizeof mismatch in CheckFirewall()
37 Revision 1.43 2009/01/13 05:31:35 mkrochma
38 <rdar://problem/6491367> Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy
40 Revision 1.42 2007/02/14 01:58:19 cheshire
41 <rdar://problem/4995831> Don't delete Unix Domain Socket on exit if we didn't create it on startup
43 Revision 1.41 2007/02/06 19:06:49 cheshire
44 <rdar://problem/3956518> Need to go native with launchd
46 Revision 1.40 2007/01/05 05:46:08 cheshire
47 Add mDNS *const m parameter to udsserver_handle_configchange()
49 Revision 1.39 2006/08/14 23:26:07 cheshire
50 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
52 Revision 1.38 2005/10/05 20:55:15 herscher
53 <rdar://problem/4096464> Don't call SetLLRoute on loopback interface
55 Revision 1.37 2005/10/05 18:05:28 herscher
56 <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.
58 Revision 1.36 2005/09/11 22:12:42 herscher
59 <rdar://problem/4247793> Remove dependency on WMI. Ensure that the Windows firewall is turned on before trying to configure it.
61 Revision 1.35 2005/06/30 18:29:49 shersche
62 <rdar://problem/4090059> Don't overwrite the localized service description text
64 Revision 1.34 2005/04/22 07:34:23 shersche
65 Check an interface's address and make sure it's valid before using it to set link-local routes.
67 Revision 1.33 2005/04/13 17:48:23 shersche
68 <rdar://problem/4079667> Make sure there is only one default route for link-local addresses.
70 Revision 1.32 2005/04/06 01:32:05 shersche
71 Remove default route for link-local addressing when another interface comes up with a routable IPv4 address
73 Revision 1.31 2005/04/06 01:00:11 shersche
74 <rdar://problem/4080127> GetFullPathName() should be passed the number of TCHARs in the path buffer, not the size in bytes of the path buffer.
76 Revision 1.30 2005/04/06 00:52:43 shersche
77 <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.
79 Revision 1.29 2005/03/06 05:21:56 shersche
80 <rdar://problem/4037635> Fix corrupt UTF-8 name when non-ASCII system name used, enabled unicode support
82 Revision 1.28 2005/03/03 02:27:24 shersche
83 Include the RegNames.h header file for names of registry keys
85 Revision 1.27 2005/03/02 20:12:59 shersche
88 Revision 1.26 2005/02/15 08:00:27 shersche
89 <rdar://problem/4007151> Update name
91 Revision 1.25 2005/02/10 22:35:36 cheshire
92 <rdar://problem/3727944> Update name
94 Revision 1.24 2005/01/27 20:02:43 cheshire
95 udsSupportRemoveFDFromEventLoop() needs to close the SocketRef as well
97 Revision 1.23 2005/01/25 08:14:15 shersche
98 Change CacheRecord to CacheEntity
100 Revision 1.22 2004/12/10 13:18:40 cheshire
101 Create no-op function RecordUpdatedNiceLabel(), required by uds_daemon.c
103 Revision 1.21 2004/11/10 04:03:41 shersche
104 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.
106 Revision 1.20 2004/10/14 21:44:05 shersche
107 <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.
110 Revision 1.19 2004/10/12 17:59:55 shersche
111 <rdar://problem/3718122> Disable routing table modifications when Nortel VPN adapter is active
114 Revision 1.18 2004/10/11 21:57:50 shersche
115 <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.
118 Revision 1.17 2004/09/17 01:08:58 cheshire
119 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
120 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
121 declared in that file are ONLY appropriate to single-address-space embedded applications.
122 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
124 Revision 1.16 2004/09/16 18:49:34 shersche
125 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.
127 Revision 1.15 2004/09/15 17:13:33 shersche
130 Revision 1.14 2004/09/15 09:37:25 shersche
131 Add SharedAccess to dependency list, call CheckFirewall after sending status back to SCM
133 Revision 1.13 2004/09/13 07:35:10 shersche
134 <rdar://problem/3762235> Add mDNSResponder to Windows Firewall application list if SP2 is detected and app hasn't been added before
137 Revision 1.12 2004/09/11 21:18:32 shersche
138 <rdar://problem/3779502> Add route to ARP everything when a 169.254.x.x address is selected
141 Revision 1.11 2004/09/11 05:39:19 shersche
142 <rdar://problem/3780203> Detect power managment state changes, calling mDNSCoreMachineSleep(m, true) on sleep, and mDNSCoreMachineSleep(m, false) on resume
145 Revision 1.10 2004/08/16 21:45:24 shersche
146 Use the full pathname of executable when calling CreateService()
147 Submitted by: prepin@zetron.com
149 Revision 1.9 2004/08/11 01:59:41 cheshire
150 Remove "mDNS *globalInstance" parameter from udsserver_init()
152 Revision 1.8 2004/08/05 05:40:05 shersche
153 <rdar://problem/3751566> Only invoke SetConsoleCtrlHandler when running directly from command line.
154 <rdar://problem/3751481> Invoke udsserver_handle_configchange() when the computer description changes
155 Bug #: 3751481, 3751566
157 Revision 1.7 2004/07/26 05:35:07 shersche
158 ignore non-enet interfaces when setting up link-local routing
160 Revision 1.6 2004/07/20 06:48:26 shersche
161 <rdar://problem/3718122> Allow registry entries to dictate whether to manage link local routing
164 Revision 1.5 2004/07/09 19:08:07 shersche
165 <rdar://problem/3713762> ServiceSetupEventLogging() errors are handled gracefully
168 Revision 1.4 2004/06/24 20:58:15 shersche
169 Fix compiler error in Release build
170 Submitted by: herscher
172 Revision 1.3 2004/06/24 15:28:53 shersche
173 Automatically setup routes to link-local addresses upon interface list change events.
174 Submitted by: herscher
176 Revision 1.2 2004/06/23 16:56:00 shersche
177 <rdar://problem/3697326> locked call to udsserver_idle().
179 Submitted by: herscher
181 Revision 1.1 2004/06/18 04:16:41 rpantos
184 Revision 1.1 2004/01/30 02:58:39 bradley
185 mDNSResponder Windows Service. Provides global Bonjour support with an IPC interface.
195 #include "CommonServices.h"
196 #include "DebugServices.h"
197 #include "RegNames.h"
199 #include "uds_daemon.h"
200 #include "GenLinkedList.h"
202 #include "Resource.h"
204 #include "mDNSEmbeddedAPI.h"
205 #include "mDNSWin32.h"
207 #include "Firewall.h"
209 #if( !TARGET_OS_WINDOWS_CE )
212 #include <ipExport.h>
214 #include <ws2ipdef.h>
215 #include <iphlpapi.h>
216 #include <netioapi.h>
220 #ifndef HeapEnableTerminationOnCorruption
221 # define HeapEnableTerminationOnCorruption (HEAP_INFORMATION_CLASS)1
225 #pragma mark == Constants ==
228 //===========================================================================================================================
230 //===========================================================================================================================
232 #define DEBUG_NAME "[Server] "
233 #define kServiceFirewallName L"Bonjour"
234 #define kServiceDependencies TEXT("Tcpip\0\0")
235 #define kDNSServiceCacheEntryCountDefault 512
236 #define kRetryFirewallPeriod 30 * 1000
237 #define kDefValueSize MAX_PATH + 1
239 #define kDefaultRouteMetric 399
241 #define RR_CACHE_SIZE 500
242 static CacheEntity gRRCache
[RR_CACHE_SIZE
];
244 #pragma mark == Structures ==
247 //===========================================================================================================================
249 //===========================================================================================================================
250 //---------------------------------------------------------------------------------------------------------------------------
251 /*! @typedef EventSourceFlags
253 @abstract Session flags.
255 @constant EventSourceFlagsNone No flags.
256 @constant EventSourceFlagsThreadDone Thread is no longer active.
257 @constant EventSourceFlagsNoClose Do not close the session when the thread exits.
258 @constant EventSourceFinalized Finalize has been called for this session
261 typedef uint32_t EventSourceFlags
;
263 #define EventSourceFlagsNone 0
264 #define EventSourceFlagsThreadDone ( 1 << 2 )
265 #define EventSourceFlagsNoClose ( 1 << 3 )
266 #define EventSourceFinalized ( 1 << 4 )
269 typedef struct Win32EventSource
271 EventSourceFlags flags
;
276 udsEventCallback callback
;
281 struct Win32EventSource
* next
;
286 #pragma mark == Prototypes ==
289 //===========================================================================================================================
291 //===========================================================================================================================
293 int __cdecl
wmain( int argc
, LPTSTR argv
[] );
295 int __cdecl
main( int argc
, char *argv
[] );
297 static void Usage( void );
298 static BOOL WINAPI
ConsoleControlHandler( DWORD inControlEvent
);
299 static OSStatus
InstallService( LPCTSTR inName
, LPCTSTR inDisplayName
, LPCTSTR inDescription
, LPCTSTR inPath
);
300 static OSStatus
RemoveService( LPCTSTR inName
);
301 static OSStatus
SetServiceParameters();
302 static OSStatus
GetServiceParameters();
303 static OSStatus
CheckFirewall();
304 static OSStatus
SetServiceInfo( SC_HANDLE inSCM
, LPCTSTR inServiceName
, LPCTSTR inDescription
);
305 static void ReportStatus( int inType
, const char *inFormat
, ... );
306 static OSStatus
RunDirect( int argc
, LPTSTR argv
[] );
308 static void WINAPI
ServiceMain( DWORD argc
, LPTSTR argv
[] );
309 static OSStatus
ServiceSetupEventLogging( void );
310 static DWORD WINAPI
ServiceControlHandler( DWORD inControl
, DWORD inEventType
, LPVOID inEventData
, LPVOID inContext
);
312 static OSStatus
ServiceRun( int argc
, LPTSTR argv
[] );
313 static void ServiceStop( void );
315 static OSStatus
ServiceSpecificInitialize( int argc
, LPTSTR argv
[] );
316 static OSStatus
ServiceSpecificRun( int argc
, LPTSTR argv
[] );
317 static OSStatus
ServiceSpecificStop( void );
318 static void ServiceSpecificFinalize( int argc
, LPTSTR argv
[] );
319 static mStatus
EventSourceFinalize(Win32EventSource
* source
);
320 static void EventSourceLock();
321 static void EventSourceUnlock();
322 static mDNSs32
udsIdle(mDNS
* const inMDNS
, mDNSs32 interval
);
323 static void CoreCallback(mDNS
* const inMDNS
, mStatus result
);
324 static void HostDescriptionChanged(mDNS
* const inMDNS
);
325 static OSStatus
GetRouteDestination(DWORD
* ifIndex
, DWORD
* address
);
326 static OSStatus
SetLLRoute( mDNS
* const inMDNS
);
327 static bool HaveRoute( PMIB_IPFORWARDROW rowExtant
, unsigned long addr
, unsigned long metric
);
328 static bool IsValidAddress( const char * addr
);
329 static bool IsNortelVPN( IP_ADAPTER_INFO
* pAdapter
);
330 static bool IsJuniperVPN( IP_ADAPTER_INFO
* pAdapter
);
331 static bool IsCiscoVPN( IP_ADAPTER_INFO
* pAdapter
);
332 static const char * strnistr( const char * string
, const char * subString
, size_t max
);
335 # define StrLen(X) wcslen(X)
336 # define StrCmp(X,Y) wcscmp(X,Y)
338 # define StrLen(X) strlen(X)
339 # define StrCmp(X,Y) strcmp(X,Y)
343 #define kLLNetworkAddr "169.254.0.0"
344 #define kLLNetworkAddrMask "255.255.0.0"
347 #include "mDNSEmbeddedAPI.h"
350 #pragma mark == Globals ==
353 //===========================================================================================================================
355 //===========================================================================================================================
356 #define gMDNSRecord mDNSStorage
357 DEBUG_LOCAL mDNS_PlatformSupport gPlatformStorage
;
358 DEBUG_LOCAL BOOL gServiceQuietMode
= FALSE
;
359 DEBUG_LOCAL SERVICE_TABLE_ENTRY gServiceDispatchTable
[] =
361 { kServiceName
, ServiceMain
},
364 DEBUG_LOCAL SERVICE_STATUS gServiceStatus
;
365 DEBUG_LOCAL SERVICE_STATUS_HANDLE gServiceStatusHandle
= NULL
;
366 DEBUG_LOCAL HANDLE gServiceEventSource
= NULL
;
367 DEBUG_LOCAL
bool gServiceAllowRemote
= false;
368 DEBUG_LOCAL
int gServiceCacheEntryCount
= 0; // 0 means to use the DNS-SD default.
369 DEBUG_LOCAL
bool gServiceManageLLRouting
= true;
370 DEBUG_LOCAL
int gWaitCount
= 0;
371 DEBUG_LOCAL HANDLE
* gWaitList
= NULL
;
372 DEBUG_LOCAL HANDLE gStopEvent
= NULL
;
373 DEBUG_LOCAL CRITICAL_SECTION gEventSourceLock
;
374 DEBUG_LOCAL GenLinkedList gEventSources
;
375 DEBUG_LOCAL BOOL gRetryFirewall
= FALSE
;
376 DEBUG_LOCAL DWORD gOSMajorVersion
;
377 DEBUG_LOCAL DWORD gOSMinorVersion
;
379 typedef DWORD ( WINAPI
* GetIpInterfaceEntryFunctionPtr
)( PMIB_IPINTERFACE_ROW
);
380 mDNSlocal HMODULE gIPHelperLibraryInstance
= NULL
;
381 mDNSlocal GetIpInterfaceEntryFunctionPtr gGetIpInterfaceEntryFunctionPtr
= NULL
;
388 //===========================================================================================================================
390 //===========================================================================================================================
392 int __cdecl
wmain( int argc
, wchar_t * argv
[] )
394 int __cdecl
main( int argc
, char *argv
[] )
402 HeapSetInformation( NULL
, HeapEnableTerminationOnCorruption
, NULL
, 0 );
404 debug_initialize( kDebugOutputTypeMetaConsole
);
405 debug_set_property( kDebugPropertyTagPrintLevel
, kDebugLevelVerbose
);
407 // Default to automatically starting the service dispatcher if no extra arguments are specified.
409 start
= ( argc
<= 1 );
413 for( i
= 1; i
< argc
; ++i
)
415 if( StrCmp( argv
[ i
], TEXT("-install") ) == 0 ) // Install
420 LoadString( GetModuleHandle( NULL
), IDS_SERVICE_DESCRIPTION
, desc
, sizeof( desc
) );
421 err
= InstallService( kServiceName
, kServiceName
, desc
, argv
[0] );
424 ReportStatus( EVENTLOG_ERROR_TYPE
, "install service failed (%d)\n", err
);
428 else if( StrCmp( argv
[ i
], TEXT("-remove") ) == 0 ) // Remove
430 err
= RemoveService( kServiceName
);
433 ReportStatus( EVENTLOG_ERROR_TYPE
, "remove service failed (%d)\n", err
);
437 else if( StrCmp( argv
[ i
], TEXT("-start") ) == 0 ) // Start
441 else if( StrCmp( argv
[ i
], TEXT("-server") ) == 0 ) // Server
443 err
= RunDirect( argc
, argv
);
446 ReportStatus( EVENTLOG_ERROR_TYPE
, "run service directly failed (%d)\n", err
);
450 else if( StrCmp( argv
[ i
], TEXT("-q") ) == 0 ) // Quiet Mode (toggle)
452 gServiceQuietMode
= !gServiceQuietMode
;
454 else if( ( StrCmp( argv
[ i
], TEXT("-help") ) == 0 ) || // Help
455 ( StrCmp( argv
[ i
], TEXT("-h") ) == 0 ) )
469 // Start the service dispatcher if requested. This does not return until all services have terminated. If any
470 // global initialization is needed, it should be done before starting the service dispatcher, but only if it
471 // will take less than 30 seconds. Otherwise, use a separate thread for it and start the dispatcher immediately.
475 ok
= StartServiceCtrlDispatcher( gServiceDispatchTable
);
476 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kInUseErr
);
479 ReportStatus( EVENTLOG_ERROR_TYPE
, "start service dispatcher failed (%d)\n", err
);
486 dlog( kDebugLevelTrace
, DEBUG_NAME
"exited (%d %m)\n", err
, err
);
490 //===========================================================================================================================
492 //===========================================================================================================================
494 static void Usage( void )
496 fprintf( stderr
, "\n" );
497 fprintf( stderr
, "mDNSResponder 1.0d1\n" );
498 fprintf( stderr
, "\n" );
499 fprintf( stderr
, " <no args> Runs the service normally\n" );
500 fprintf( stderr
, " -install Creates the service and starts it\n" );
501 fprintf( stderr
, " -remove Stops the service and deletes it\n" );
502 fprintf( stderr
, " -start Starts the service dispatcher after processing all other arguments\n" );
503 fprintf( stderr
, " -server Runs the service directly as a server (for debugging)\n" );
504 fprintf( stderr
, " -q Toggles Quiet Mode (no events or output)\n" );
505 fprintf( stderr
, " -remote Allow remote connections\n" );
506 fprintf( stderr
, " -cache n Number of mDNS cache entries (defaults to %d)\n", kDNSServiceCacheEntryCountDefault
);
507 fprintf( stderr
, " -h[elp] Display Help/Usage\n" );
508 fprintf( stderr
, "\n" );
511 //===========================================================================================================================
512 // ConsoleControlHandler
513 //===========================================================================================================================
515 static BOOL WINAPI
ConsoleControlHandler( DWORD inControlEvent
)
521 switch( inControlEvent
)
524 case CTRL_BREAK_EVENT
:
525 case CTRL_CLOSE_EVENT
:
526 case CTRL_LOGOFF_EVENT
:
527 case CTRL_SHUTDOWN_EVENT
:
528 err
= ServiceSpecificStop();
529 require_noerr( err
, exit
);
542 //===========================================================================================================================
544 //===========================================================================================================================
546 static OSStatus
InstallService( LPCTSTR inName
, LPCTSTR inDisplayName
, LPCTSTR inDescription
, LPCTSTR inPath
)
552 TCHAR fullPath
[ MAX_PATH
];
559 // Get a full path to the executable since a relative path may have been specified.
561 size
= GetFullPathName( inPath
, MAX_PATH
, fullPath
, &namePtr
);
562 err
= translate_errno( size
> 0, (OSStatus
) GetLastError(), kPathErr
);
563 require_noerr( err
, exit
);
565 // Create the service and start it.
567 scm
= OpenSCManager( NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
568 err
= translate_errno( scm
, (OSStatus
) GetLastError(), kOpenErr
);
569 require_noerr( err
, exit
);
571 service
= CreateService( scm
, inName
, inDisplayName
, SERVICE_ALL_ACCESS
, SERVICE_WIN32_SHARE_PROCESS
,
572 SERVICE_AUTO_START
, SERVICE_ERROR_NORMAL
, fullPath
, NULL
, NULL
, kServiceDependencies
,
574 err
= translate_errno( service
, (OSStatus
) GetLastError(), kDuplicateErr
);
575 require_noerr( err
, exit
);
577 err
= SetServiceParameters();
582 err
= SetServiceInfo( scm
, inName
, inDescription
);
586 ok
= StartService( service
, 0, NULL
);
587 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kInUseErr
);
588 require_noerr( err
, exit
);
590 ReportStatus( EVENTLOG_SUCCESS
, "installed service \"%s\"/\"%s\" at \"%s\"\n", inName
, inDisplayName
, inPath
);
596 CloseServiceHandle( service
);
600 CloseServiceHandle( scm
);
605 //===========================================================================================================================
607 //===========================================================================================================================
609 static OSStatus
RemoveService( LPCTSTR inName
)
615 SERVICE_STATUS status
;
620 // Open a connection to the service.
622 scm
= OpenSCManager( 0, 0, SC_MANAGER_ALL_ACCESS
);
623 err
= translate_errno( scm
, (OSStatus
) GetLastError(), kOpenErr
);
624 require_noerr( err
, exit
);
626 service
= OpenService( scm
, inName
, SERVICE_STOP
| SERVICE_QUERY_STATUS
| DELETE
);
627 err
= translate_errno( service
, (OSStatus
) GetLastError(), kNotFoundErr
);
628 require_noerr( err
, exit
);
630 // Stop the service, if it is not already stopped, then delete it.
632 ok
= QueryServiceStatus( service
, &status
);
633 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kAuthenticationErr
);
634 require_noerr( err
, exit
);
636 if( status
.dwCurrentState
!= SERVICE_STOPPED
)
638 ok
= ControlService( service
, SERVICE_CONTROL_STOP
, &status
);
639 check_translated_errno( ok
, (OSStatus
) GetLastError(), kAuthenticationErr
);
642 ok
= DeleteService( service
);
643 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kDeletedErr
);
644 require_noerr( err
, exit
);
646 ReportStatus( EVENTLOG_SUCCESS
, "Removed service \"%s\"\n", inName
);
652 CloseServiceHandle( service
);
656 CloseServiceHandle( scm
);
663 //===========================================================================================================================
664 // SetServiceParameters
665 //===========================================================================================================================
667 static OSStatus
SetServiceParameters()
670 DWORD valueLen
= sizeof(DWORD
);
678 // Add/Open Parameters section under service entry in registry
680 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
, &key
);
681 require_noerr( err
, exit
);
684 // If the value isn't already there, then we create it
686 err
= RegQueryValueEx(key
, kServiceManageLLRouting
, 0, &type
, (LPBYTE
) &value
, &valueLen
);
688 if (err
!= ERROR_SUCCESS
)
692 err
= RegSetValueEx( key
, kServiceManageLLRouting
, 0, REG_DWORD
, (const LPBYTE
) &value
, sizeof(DWORD
) );
693 require_noerr( err
, exit
);
708 //===========================================================================================================================
709 // GetServiceParameters
710 //===========================================================================================================================
712 static OSStatus
GetServiceParameters()
723 // Add/Open Parameters section under service entry in registry
725 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
, &key
);
726 require_noerr( err
, exit
);
728 valueLen
= sizeof(DWORD
);
729 err
= RegQueryValueEx(key
, kServiceManageLLRouting
, 0, &type
, (LPBYTE
) &value
, &valueLen
);
730 if (err
== ERROR_SUCCESS
)
732 gServiceManageLLRouting
= (value
) ? true : false;
735 valueLen
= sizeof(DWORD
);
736 err
= RegQueryValueEx(key
, kServiceCacheEntryCount
, 0, &type
, (LPBYTE
) &value
, &valueLen
);
737 if (err
== ERROR_SUCCESS
)
739 gServiceCacheEntryCount
= value
;
753 //===========================================================================================================================
755 //===========================================================================================================================
757 static OSStatus
CheckFirewall()
762 ENUM_SERVICE_STATUS
* lpService
= NULL
;
766 DWORD bytesNeeded
= 0;
768 DWORD resumeHandle
= 0;
773 BOOL isRunning
= FALSE
;
774 OSStatus err
= kUnknownErr
;
776 // Check to see if the firewall service is running. If it isn't, then
777 // we want to return immediately
779 sc
= OpenSCManager( NULL
, NULL
, SC_MANAGER_ENUMERATE_SERVICE
);
780 err
= translate_errno( sc
, GetLastError(), kUnknownErr
);
781 require_noerr( err
, exit
);
783 srvType
= SERVICE_WIN32
;
784 srvState
= SERVICE_STATE_ALL
;
788 // Call EnumServicesStatus using the handle returned by OpenSCManager
790 ok
= EnumServicesStatus ( sc
, srvType
, srvState
, lpService
, dwBytes
, &bytesNeeded
, &srvCount
, &resumeHandle
);
792 if ( ok
|| ( GetLastError() != ERROR_MORE_DATA
) )
802 dwBytes
= bytesNeeded
;
804 lpService
= ( ENUM_SERVICE_STATUS
* ) malloc( dwBytes
);
805 require_action( lpService
, exit
, err
= mStatus_NoMemoryErr
);
808 err
= translate_errno( ok
, GetLastError(), kUnknownErr
);
809 require_noerr( err
, exit
);
811 for ( i
= 0; i
< srvCount
; i
++ )
813 if ( wcscmp( lpService
[i
].lpServiceName
, L
"SharedAccess" ) == 0 )
815 if ( lpService
[i
].ServiceStatus
.dwCurrentState
== SERVICE_RUNNING
)
824 require_action( isRunning
, exit
, err
= kUnknownErr
);
826 // Check to see if we've managed the firewall.
827 // This package might have been installed, then
828 // the OS was upgraded to SP2 or above. If that's
829 // the case, then we need to manipulate the firewall
830 // so networking works correctly.
832 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
, &key
);
833 require_noerr( err
, exit
);
835 valueLen
= sizeof(DWORD
);
836 err
= RegQueryValueEx(key
, kServiceManageFirewall
, 0, &type
, (LPBYTE
) &value
, &valueLen
);
838 if ((err
!= ERROR_SUCCESS
) || (value
== 0))
840 wchar_t fullPath
[ MAX_PATH
];
843 // Get a full path to the executable
845 size
= GetModuleFileNameW( NULL
, fullPath
, MAX_PATH
);
846 err
= translate_errno( size
> 0, (OSStatus
) GetLastError(), kPathErr
);
847 require_noerr( err
, exit
);
849 err
= mDNSAddToFirewall(fullPath
, kServiceFirewallName
);
850 require_noerr( err
, exit
);
853 err
= RegSetValueEx( key
, kServiceManageFirewall
, 0, REG_DWORD
, (const LPBYTE
) &value
, sizeof( DWORD
) );
854 require_noerr( err
, exit
);
871 CloseServiceHandle ( sc
);
879 //===========================================================================================================================
881 //===========================================================================================================================
883 static OSStatus
SetServiceInfo( SC_HANDLE inSCM
, LPCTSTR inServiceName
, LPCTSTR inDescription
)
888 SERVICE_DESCRIPTION description
;
889 SERVICE_FAILURE_ACTIONS actions
;
893 check( inServiceName
);
894 check( inDescription
);
899 // Open the database (if not provided) and lock it to prevent other access while re-configuring.
903 inSCM
= OpenSCManager( NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
904 err
= translate_errno( inSCM
, (OSStatus
) GetLastError(), kOpenErr
);
905 require_noerr( err
, exit
);
908 lock
= LockServiceDatabase( inSCM
);
909 err
= translate_errno( lock
, (OSStatus
) GetLastError(), kInUseErr
);
910 require_noerr( err
, exit
);
912 // Open a handle to the service.
914 service
= OpenService( inSCM
, inServiceName
, SERVICE_CHANGE_CONFIG
|SERVICE_START
);
915 err
= translate_errno( service
, (OSStatus
) GetLastError(), kNotFoundErr
);
916 require_noerr( err
, exit
);
918 // Change the description.
920 description
.lpDescription
= (LPTSTR
) inDescription
;
921 ok
= ChangeServiceConfig2( service
, SERVICE_CONFIG_DESCRIPTION
, &description
);
922 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kParamErr
);
923 require_noerr( err
, exit
);
925 actions
.dwResetPeriod
= INFINITE
;
926 actions
.lpRebootMsg
= NULL
;
927 actions
.lpCommand
= NULL
;
928 actions
.cActions
= 1;
929 actions
.lpsaActions
= &action
;
931 action
.Type
= SC_ACTION_RESTART
;
933 ok
= ChangeServiceConfig2( service
, SERVICE_CONFIG_FAILURE_ACTIONS
, &actions
);
934 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kParamErr
);
935 require_noerr( err
, exit
);
940 // Close the service and release the lock.
944 CloseServiceHandle( service
);
948 UnlockServiceDatabase( lock
);
953 //===========================================================================================================================
955 //===========================================================================================================================
957 static void ReportStatus( int inType
, const char *inFormat
, ... )
959 if( !gServiceQuietMode
)
963 va_start( args
, inFormat
);
964 if( gServiceEventSource
)
968 const char * array
[ 1 ];
970 vsprintf( s
, inFormat
, args
);
972 ok
= ReportEventA( gServiceEventSource
, (WORD
) inType
, 0, 0x20000001L
, NULL
, 1, 0, array
, NULL
);
973 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
979 n
= vfprintf( stderr
, inFormat
, args
);
986 //===========================================================================================================================
988 //===========================================================================================================================
990 static OSStatus
RunDirect( int argc
, LPTSTR argv
[] )
998 // Install a Console Control Handler to handle things like control-c signals.
1000 ok
= SetConsoleCtrlHandler( ConsoleControlHandler
, TRUE
);
1001 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
1002 require_noerr( err
, exit
);
1004 err
= ServiceSpecificInitialize( argc
, argv
);
1005 require_noerr( err
, exit
);
1008 // Run the service. This does not return until the service quits or is stopped.
1010 ReportStatus( EVENTLOG_SUCCESS
, "Running \"%s\" service directly\n", kServiceName
);
1012 err
= ServiceSpecificRun( argc
, argv
);
1013 require_noerr( err
, exit
);
1020 ServiceSpecificFinalize( argc
, argv
);
1029 //===========================================================================================================================
1031 //===========================================================================================================================
1033 static void WINAPI
ServiceMain( DWORD argc
, LPTSTR argv
[] )
1038 err
= ServiceSetupEventLogging();
1041 err
= GetServiceParameters();
1044 // Initialize the service status and register the service control handler with the name of the service.
1046 gServiceStatus
.dwServiceType
= SERVICE_WIN32_SHARE_PROCESS
;
1047 gServiceStatus
.dwCurrentState
= 0;
1048 gServiceStatus
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
|SERVICE_ACCEPT_POWEREVENT
;
1049 gServiceStatus
.dwWin32ExitCode
= NO_ERROR
;
1050 gServiceStatus
.dwServiceSpecificExitCode
= NO_ERROR
;
1051 gServiceStatus
.dwCheckPoint
= 0;
1052 gServiceStatus
.dwWaitHint
= 0;
1054 gServiceStatusHandle
= RegisterServiceCtrlHandlerEx( argv
[ 0 ], ServiceControlHandler
, NULL
);
1055 err
= translate_errno( gServiceStatusHandle
, (OSStatus
) GetLastError(), kInUseErr
);
1056 require_noerr( err
, exit
);
1058 // Mark the service as starting.
1060 gServiceStatus
.dwCurrentState
= SERVICE_START_PENDING
;
1061 gServiceStatus
.dwCheckPoint
= 0;
1062 gServiceStatus
.dwWaitHint
= 5000; // 5 seconds
1063 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
1064 check_translated_errno( ok
, GetLastError(), kParamErr
);
1066 // Run the service. This does not return until the service quits or is stopped.
1068 err
= ServiceRun( (int) argc
, argv
);
1071 gServiceStatus
.dwWin32ExitCode
= ERROR_SERVICE_SPECIFIC_ERROR
;
1072 gServiceStatus
.dwServiceSpecificExitCode
= (DWORD
) err
;
1075 // Service-specific work is done so mark the service as stopped.
1077 gServiceStatus
.dwCurrentState
= SERVICE_STOPPED
;
1078 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
1079 check_translated_errno( ok
, GetLastError(), kParamErr
);
1081 // Note: The service status handle should not be closed according to Microsoft documentation.
1084 if( gServiceEventSource
)
1086 ok
= DeregisterEventSource( gServiceEventSource
);
1087 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
1088 gServiceEventSource
= NULL
;
1092 //===========================================================================================================================
1093 // ServiceSetupEventLogging
1094 //===========================================================================================================================
1096 static OSStatus
ServiceSetupEventLogging( void )
1101 DWORD typesSupported
;
1102 TCHAR path
[ MAX_PATH
];
1107 // Add/Open source name as a sub-key under the Application key in the EventLog registry key.
1109 s
= TEXT("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\") kServiceName
;
1110 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, s
, &key
);
1111 require_noerr( err
, exit
);
1113 // Add the name to the EventMessageFile subkey.
1116 GetModuleFileName( NULL
, path
, MAX_PATH
);
1117 n
= (DWORD
) ( ( StrLen( path
) + 1 ) * sizeof( TCHAR
) );
1118 err
= RegSetValueEx( key
, TEXT("EventMessageFile"), 0, REG_EXPAND_SZ
, (const LPBYTE
) path
, n
);
1119 require_noerr( err
, exit
);
1121 // Set the supported event types in the TypesSupported subkey.
1125 | EVENTLOG_ERROR_TYPE
1126 | EVENTLOG_WARNING_TYPE
1127 | EVENTLOG_INFORMATION_TYPE
1128 | EVENTLOG_AUDIT_SUCCESS
1129 | EVENTLOG_AUDIT_FAILURE
;
1130 err
= RegSetValueEx( key
, TEXT("TypesSupported"), 0, REG_DWORD
, (const LPBYTE
) &typesSupported
, sizeof( DWORD
) );
1131 require_noerr( err
, exit
);
1133 // Set up the event source.
1135 gServiceEventSource
= RegisterEventSource( NULL
, kServiceName
);
1136 err
= translate_errno( gServiceEventSource
, (OSStatus
) GetLastError(), kParamErr
);
1137 require_noerr( err
, exit
);
1147 //===========================================================================================================================
1148 // ServiceControlHandler
1149 //===========================================================================================================================
1151 static DWORD WINAPI
ServiceControlHandler( DWORD inControl
, DWORD inEventType
, LPVOID inEventData
, LPVOID inContext
)
1156 DEBUG_UNUSED( inEventData
);
1157 DEBUG_UNUSED( inContext
);
1162 case SERVICE_CONTROL_STOP
:
1163 dlog( kDebugLevelNotice
, DEBUG_NAME
"ServiceControlHandler: SERVICE_CONTROL_STOP\n" );
1169 case SERVICE_CONTROL_POWEREVENT
:
1171 if (inEventType
== PBT_APMSUSPEND
)
1173 mDNSCoreMachineSleep(&gMDNSRecord
, TRUE
);
1175 else if (inEventType
== PBT_APMRESUMESUSPEND
)
1177 mDNSCoreMachineSleep(&gMDNSRecord
, FALSE
);
1183 dlog( kDebugLevelNotice
, DEBUG_NAME
"ServiceControlHandler: event (0x%08X)\n", inControl
);
1187 if( setStatus
&& gServiceStatusHandle
)
1189 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
1190 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
1196 //===========================================================================================================================
1198 //===========================================================================================================================
1200 static OSStatus
ServiceRun( int argc
, LPTSTR argv
[] )
1206 DEBUG_UNUSED( argc
);
1207 DEBUG_UNUSED( argv
);
1209 initialized
= FALSE
;
1211 // <rdar://problem/5727548> Make the service as running before we call ServiceSpecificInitialize. We've
1212 // had reports that some machines with McAfee firewall installed cause a problem with iTunes installation.
1213 // We think that the firewall product is interferring with code in ServiceSpecificInitialize. So as a
1214 // simple workaround, we'll mark us as running *before* we call ServiceSpecificInitialize. This will unblock
1215 // any installers that are waiting for our state to change.
1217 gServiceStatus
.dwCurrentState
= SERVICE_RUNNING
;
1218 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
1219 check_translated_errno( ok
, GetLastError(), kParamErr
);
1221 // Initialize the service-specific stuff
1223 err
= ServiceSpecificInitialize( argc
, argv
);
1224 require_noerr( err
, exit
);
1227 err
= CheckFirewall();
1232 gRetryFirewall
= TRUE
;
1235 // Run the service-specific stuff. This does not return until the service quits or is stopped.
1237 ReportStatus( EVENTLOG_INFORMATION_TYPE
, "mDNSResponder started\n" );
1238 err
= ServiceSpecificRun( argc
, argv
);
1239 ReportStatus( EVENTLOG_INFORMATION_TYPE
, "mDNSResponder stopped (%d)\n", err
);
1240 require_noerr( err
, exit
);
1242 // Service stopped. Clean up and we're done.
1247 ServiceSpecificFinalize( argc
, argv
);
1252 //===========================================================================================================================
1254 //===========================================================================================================================
1256 static void ServiceStop( void )
1261 // Signal the event to cause the service to exit.
1263 if( gServiceStatusHandle
)
1265 gServiceStatus
.dwCurrentState
= SERVICE_STOP_PENDING
;
1266 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
1267 check_translated_errno( ok
, GetLastError(), kParamErr
);
1270 err
= ServiceSpecificStop();
1276 #pragma mark == Service Specific ==
1279 //===========================================================================================================================
1280 // ServiceSpecificInitialize
1281 //===========================================================================================================================
1283 static OSStatus
ServiceSpecificInitialize( int argc
, LPTSTR argv
[] )
1285 OSVERSIONINFO osInfo
;
1289 DEBUG_UNUSED( argc
);
1290 DEBUG_UNUSED( argv
);
1292 mDNSPlatformMemZero( &gMDNSRecord
, sizeof gMDNSRecord
);
1293 mDNSPlatformMemZero( &gPlatformStorage
, sizeof gPlatformStorage
);
1295 gPlatformStorage
.idleThreadCallback
= udsIdle
;
1296 gPlatformStorage
.hostDescriptionChangedCallback
= HostDescriptionChanged
;
1298 InitializeCriticalSection(&gEventSourceLock
);
1300 gStopEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1301 err
= translate_errno( gStopEvent
, errno_compat(), kNoResourcesErr
);
1302 require_noerr( err
, exit
);
1304 err
= mDNS_Init( &gMDNSRecord
, &gPlatformStorage
, gRRCache
, RR_CACHE_SIZE
, mDNS_Init_AdvertiseLocalAddresses
, CoreCallback
, mDNS_Init_NoInitCallbackContext
);
1305 require_noerr( err
, exit
);
1307 err
= udsserver_init(mDNSNULL
, 0);
1308 require_noerr( err
, exit
);
1311 // Get the version of Windows that we're running on
1313 osInfo
.dwOSVersionInfoSize
= sizeof( OSVERSIONINFO
);
1314 ok
= GetVersionEx( &osInfo
);
1315 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
1316 require_noerr( err
, exit
);
1317 gOSMajorVersion
= osInfo
.dwMajorVersion
;
1318 gOSMinorVersion
= osInfo
.dwMinorVersion
;
1320 SetLLRoute( &gMDNSRecord
);
1325 ServiceSpecificFinalize( argc
, argv
);
1330 //===========================================================================================================================
1331 // ServiceSpecificRun
1332 //===========================================================================================================================
1334 static OSStatus
ServiceSpecificRun( int argc
, LPTSTR argv
[] )
1339 DEBUG_UNUSED( argc
);
1340 DEBUG_UNUSED( argv
);
1342 // Main event loop. Process connection requests and state changes (i.e. quit).
1344 timeout
= ( gRetryFirewall
) ? kRetryFirewallPeriod
: INFINITE
;
1346 while( (result
= WaitForSingleObject( gStopEvent
, timeout
) ) != WAIT_OBJECT_0
)
1348 if ( result
== WAIT_TIMEOUT
)
1352 err
= CheckFirewall();
1359 // Unexpected wait result.
1360 dlog( kDebugLevelWarning
, DEBUG_NAME
"%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__
, result
);
1367 //===========================================================================================================================
1368 // ServiceSpecificStop
1369 //===========================================================================================================================
1371 static OSStatus
ServiceSpecificStop( void )
1376 ok
= SetEvent(gStopEvent
);
1377 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
1378 require_noerr( err
, exit
);
1383 //===========================================================================================================================
1384 // ServiceSpecificFinalize
1385 //===========================================================================================================================
1387 static void ServiceSpecificFinalize( int argc
, LPTSTR argv
[] )
1389 DEBUG_UNUSED( argc
);
1390 DEBUG_UNUSED( argv
);
1393 // clean up any open sessions
1395 while (gEventSources
.Head
)
1397 EventSourceFinalize((Win32EventSource
*) gEventSources
.Head
);
1400 // give a chance for the udsserver code to clean up
1405 // and finally close down the mDNSCore
1407 mDNS_Close(&gMDNSRecord
);
1410 // clean up the event sources mutex...no one should be using it now
1412 DeleteCriticalSection(&gEventSourceLock
);
1415 // clean up loaded library
1418 if( gIPHelperLibraryInstance
)
1420 gGetIpInterfaceEntryFunctionPtr
= NULL
;
1422 FreeLibrary( gIPHelperLibraryInstance
);
1423 gIPHelperLibraryInstance
= NULL
;
1429 CoreCallback(mDNS
* const inMDNS
, mStatus status
)
1431 if (status
== mStatus_ConfigChanged
)
1433 SetLLRoute( inMDNS
);
1439 udsIdle(mDNS
* const inMDNS
, mDNSs32 interval
)
1441 DEBUG_UNUSED( inMDNS
);
1444 // rdar://problem/3697326
1446 // udsserver_idle wasn't being locked. This resulted
1447 // in multiple threads contesting for the all_requests
1448 // data structure in uds_daemon.c
1450 mDNSPlatformLock(&gMDNSRecord
);
1452 interval
= udsserver_idle(interval
);
1454 mDNSPlatformUnlock(&gMDNSRecord
);
1461 HostDescriptionChanged(mDNS
* const inMDNS
)
1463 DEBUG_UNUSED( inMDNS
);
1465 udsserver_handle_configchange(inMDNS
);
1469 mDNSlocal
unsigned WINAPI
1470 udsSocketThread(LPVOID inParam
)
1472 Win32EventSource
* source
= (Win32EventSource
*) inParam
;
1473 DWORD threadID
= GetCurrentThreadId();
1478 bool locked
= false;
1481 waitCount
= source
->waitCount
;
1482 waitList
[0] = source
->waitList
[0];
1483 waitList
[1] = source
->waitList
[1];
1484 done
= (bool) (source
->flags
& EventSourceFinalized
);
1490 result
= WaitForMultipleObjects(waitCount
, waitList
, FALSE
, INFINITE
);
1492 mDNSPlatformLock(&gMDNSRecord
);
1495 // <rdar://problem/3838237>
1497 // Look up the source by the thread id. This will ensure that the
1498 // source is still extant. It could already have been deleted
1499 // by the processing thread.
1504 for (source
= gEventSources
.Head
; source
; source
= source
->next
)
1506 if (source
->threadID
== threadID
)
1512 EventSourceUnlock();
1522 if (result
== WAIT_OBJECT_0
)
1524 source
->callback( (int) source
->sock
, 0, source
->context
);
1529 else if (result
== WAIT_OBJECT_0
+ 1)
1532 // this is a bit of a hack. we want to clean up the internal data structures
1533 // so we'll go in here and it will clean up for us
1535 shutdown(source
->sock
, 2);
1536 source
->callback( (int) source
->sock
, 0, source
->context
);
1542 // Unexpected wait result.
1543 dlog( kDebugLevelWarning
, DEBUG_NAME
"%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__
, result
);
1547 done
= (bool) (source
->flags
& EventSourceFinalized
);
1549 mDNSPlatformUnlock(&gMDNSRecord
);
1554 source
->flags
|= EventSourceFlagsThreadDone
;
1555 safeToClose
= !( source
->flags
& EventSourceFlagsNoClose
);
1556 EventSourceUnlock();
1560 EventSourceFinalize( source
);
1567 mDNSPlatformUnlock(&gMDNSRecord
);
1570 _endthreadex_compat( (unsigned) err
);
1571 return( (unsigned) err
);
1576 udsSupportAddFDToEventLoop( SocketRef fd
, udsEventCallback callback
, void *context
)
1578 Win32EventSource
* newSource
;
1582 newSource
= malloc(sizeof(Win32EventSource
));
1583 require_action( newSource
, exit
, err
= mStatus_NoMemoryErr
);
1584 mDNSPlatformMemZero(newSource
, sizeof(Win32EventSource
));
1586 newSource
->flags
= 0;
1587 newSource
->sock
= (SOCKET
) fd
;
1588 newSource
->callback
= callback
;
1589 newSource
->context
= context
;
1591 newSource
->socketEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1592 err
= translate_errno( newSource
->socketEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1593 require_noerr( err
, exit
);
1595 newSource
->closeEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1596 err
= translate_errno( newSource
->closeEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1597 require_noerr( err
, exit
);
1599 err
= WSAEventSelect(newSource
->sock
, newSource
->socketEvent
, FD_ACCEPT
|FD_READ
|FD_CLOSE
);
1600 err
= translate_errno( err
== 0, errno_compat(), kNoResourcesErr
);
1601 require_noerr( err
, exit
);
1603 newSource
->waitCount
= 0;
1604 newSource
->waitList
[ newSource
->waitCount
++ ] = newSource
->socketEvent
;
1605 newSource
->waitList
[ newSource
->waitCount
++ ] = newSource
->closeEvent
;
1612 // add the event source to the end of the list, while checking
1613 // to see if the list needs to be initialized
1615 if ( gEventSources
.LinkOffset
== 0)
1617 InitLinkedList( &gEventSources
, offsetof( Win32EventSource
, next
));
1620 AddToTail( &gEventSources
, newSource
);
1623 // no longer using the list
1625 EventSourceUnlock();
1627 // Create thread with _beginthreadex() instead of CreateThread() to avoid memory leaks when using static run-time
1628 // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
1629 // Create the thread suspended then resume it so the thread handle and ID are valid before the thread starts running.
1630 newSource
->threadHandle
= (HANDLE
) _beginthreadex_compat( NULL
, 0, udsSocketThread
, newSource
, CREATE_SUSPENDED
, &newSource
->threadID
);
1631 err
= translate_errno( newSource
->threadHandle
, (mStatus
) GetLastError(), kUnknownErr
);
1632 require_noerr( err
, exit
);
1634 result
= ResumeThread( newSource
->threadHandle
);
1635 err
= translate_errno( result
!= (DWORD
) -1, errno_compat(), kNoResourcesErr
);
1636 require_noerr( err
, exit
);
1640 if (err
&& newSource
)
1642 EventSourceFinalize(newSource
);
1650 udsSupportRemoveFDFromEventLoop( SocketRef fd
) // Note: This also CLOSES the socket
1652 Win32EventSource
* source
;
1653 mStatus err
= mStatus_NoError
;
1656 // find the event source
1660 for (source
= gEventSources
.Head
; source
; source
= source
->next
)
1662 if (source
->sock
== (SOCKET
) fd
)
1669 // if we found him, finalize him
1673 EventSourceFinalize(source
);
1677 // done with the list
1679 EventSourceUnlock();
1687 mDNSexport
void RecordUpdatedNiceLabel(mDNS
*const m
, mDNSs32 delay
)
1696 EventSourceFinalize(Win32EventSource
* source
)
1700 Win32EventSource
* inserted
;
1709 // Find the session in the list.
1714 for( inserted
= (Win32EventSource
*) gEventSources
.Head
; inserted
; inserted
= inserted
->next
)
1716 if( inserted
== source
)
1721 require_action( inserted
, exit
, err
= kNotFoundErr
);
1724 // note that we've had finalize called
1726 source
->flags
|= EventSourceFinalized
;
1728 // If we're being called from the same thread as the session (e.g. message callback is closing the session) then
1729 // we must defer the close until the thread is done because the thread is still using the session object.
1732 threadID
= GetCurrentThreadId();
1733 sameThread
= source
->threadHandle
&& ( threadID
== source
->threadID
);
1734 if( sameThread
&& !( source
->flags
& EventSourceFlagsThreadDone
) )
1736 source
->flags
&= ~EventSourceFlagsNoClose
;
1740 // If the thread we're not being called from the session thread, but the thread has already marked itself as
1741 // as done (e.g. session closed from something like a peer disconnect and at the same time the client also
1742 // tried to close) then we only want to continue with the close if the thread is not going to close itself.
1744 if( !sameThread
&& ( source
->flags
& EventSourceFlagsThreadDone
) && !( source
->flags
& EventSourceFlagsNoClose
) )
1749 // Signal a close so the thread exits.
1751 if( source
->closeEvent
)
1753 ok
= SetEvent( source
->closeEvent
);
1754 check_translated_errno( ok
, errno_compat(), kUnknownErr
);
1762 source
->flags
|= EventSourceFlagsNoClose
;
1764 // Remove the session from the list.
1765 RemoveFromList(&gEventSources
, source
);
1767 EventSourceUnlock();
1770 // Wait for the thread to exit. Give up after 3 seconds to handle a hung thread.
1772 if( source
->threadHandle
&& ( threadID
!= source
->threadID
) )
1774 result
= WaitForSingleObject( source
->threadHandle
, 3 * 1000 );
1775 check_translated_errno( result
== WAIT_OBJECT_0
, (OSStatus
) GetLastError(), result
);
1778 // Release the thread.
1780 if( source
->threadHandle
)
1782 ok
= CloseHandle( source
->threadHandle
);
1783 check_translated_errno( ok
, errno_compat(), kUnknownErr
);
1784 source
->threadHandle
= NULL
;
1787 // Release the socket event.
1789 if( source
->socketEvent
)
1791 ok
= CloseHandle( source
->socketEvent
);
1792 check_translated_errno( ok
, errno_compat(), kUnknownErr
);
1793 source
->socketEvent
= NULL
;
1796 // Release the close event.
1798 if( source
->closeEvent
)
1800 ok
= CloseHandle( source
->closeEvent
);
1801 check_translated_errno( ok
, errno_compat(), kUnknownErr
);
1802 source
->closeEvent
= NULL
;
1805 // Release the memory used by the object.
1810 dlog( kDebugLevelNotice
, DEBUG_NAME
"session closed\n" );
1816 EventSourceUnlock();
1826 EnterCriticalSection(&gEventSourceLock
);
1833 LeaveCriticalSection(&gEventSourceLock
);
1837 //===========================================================================================================================
1839 //===========================================================================================================================
1842 HaveRoute( PMIB_IPFORWARDROW rowExtant
, unsigned long addr
, unsigned long metric
)
1844 PMIB_IPFORWARDTABLE pIpForwardTable
= NULL
;
1846 BOOL bOrder
= FALSE
;
1849 unsigned long int i
;
1852 // Find out how big our buffer needs to be.
1854 err
= GetIpForwardTable(NULL
, &dwSize
, bOrder
);
1855 require_action( err
== ERROR_INSUFFICIENT_BUFFER
, exit
, err
= kUnknownErr
);
1858 // Allocate the memory for the table
1860 pIpForwardTable
= (PMIB_IPFORWARDTABLE
) malloc( dwSize
);
1861 require_action( pIpForwardTable
, exit
, err
= kNoMemoryErr
);
1864 // Now get the table.
1866 err
= GetIpForwardTable(pIpForwardTable
, &dwSize
, bOrder
);
1867 require_noerr( err
, exit
);
1870 // Search for the row in the table we want.
1872 for ( i
= 0; i
< pIpForwardTable
->dwNumEntries
; i
++)
1874 if ( ( pIpForwardTable
->table
[i
].dwForwardDest
== addr
) && ( !metric
|| ( pIpForwardTable
->table
[i
].dwForwardMetric1
== metric
) ) )
1876 memcpy( rowExtant
, &(pIpForwardTable
->table
[i
]), sizeof(*rowExtant
) );
1884 if ( pIpForwardTable
!= NULL
)
1886 free(pIpForwardTable
);
1893 //===========================================================================================================================
1895 //===========================================================================================================================
1898 IsValidAddress( const char * addr
)
1900 return ( addr
&& ( strcmp( addr
, "0.0.0.0" ) != 0 ) ) ? true : false;
1904 //===========================================================================================================================
1905 // GetAdditionalMetric
1906 //===========================================================================================================================
1909 GetAdditionalMetric( DWORD ifIndex
)
1913 if( !gIPHelperLibraryInstance
)
1915 gIPHelperLibraryInstance
= LoadLibrary( TEXT( "Iphlpapi" ) );
1917 gGetIpInterfaceEntryFunctionPtr
=
1918 (GetIpInterfaceEntryFunctionPtr
) GetProcAddress( gIPHelperLibraryInstance
, "GetIpInterfaceEntry" );
1920 if( !gGetIpInterfaceEntryFunctionPtr
)
1924 ok
= FreeLibrary( gIPHelperLibraryInstance
);
1925 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
1926 gIPHelperLibraryInstance
= NULL
;
1930 if ( gGetIpInterfaceEntryFunctionPtr
)
1932 MIB_IPINTERFACE_ROW row
;
1935 ZeroMemory( &row
, sizeof( MIB_IPINTERFACE_ROW
) );
1936 row
.Family
= AF_INET
;
1937 row
.InterfaceIndex
= ifIndex
;
1938 err
= gGetIpInterfaceEntryFunctionPtr( &row
);
1939 require_noerr( err
, exit
);
1940 metric
= row
.Metric
+ 256;
1949 //===========================================================================================================================
1951 //===========================================================================================================================
1954 SetLLRoute( mDNS
* const inMDNS
)
1956 OSStatus err
= kNoErr
;
1958 DEBUG_UNUSED( inMDNS
);
1961 // <rdar://problem/4096464> Don't call SetLLRoute on loopback
1962 // <rdar://problem/6885843> Default route on Windows 7 breaks network connectivity
1964 // Don't mess w/ the routing table on Vista and later OSes, as
1965 // they have a permanent route to link-local addresses. Otherwise,
1966 // set a route to link local addresses (169.254.0.0)
1968 if ( ( gOSMajorVersion
< 6 ) && gServiceManageLLRouting
&& !gPlatformStorage
.registeredLoopback4
)
1971 MIB_IPFORWARDROW rowExtant
;
1973 MIB_IPFORWARDROW row
;
1975 ZeroMemory(&row
, sizeof(row
));
1977 err
= GetRouteDestination(&ifIndex
, &row
.dwForwardNextHop
);
1978 require_noerr( err
, exit
);
1979 row
.dwForwardDest
= inet_addr(kLLNetworkAddr
);
1980 row
.dwForwardIfIndex
= ifIndex
;
1981 row
.dwForwardMask
= inet_addr(kLLNetworkAddrMask
);
1982 row
.dwForwardType
= 3;
1983 row
.dwForwardProto
= MIB_IPPROTO_NETMGMT
;
1984 row
.dwForwardAge
= 0;
1985 row
.dwForwardPolicy
= 0;
1986 row
.dwForwardMetric1
= 20 + GetAdditionalMetric( ifIndex
);
1987 row
.dwForwardMetric2
= (DWORD
) - 1;
1988 row
.dwForwardMetric3
= (DWORD
) - 1;
1989 row
.dwForwardMetric4
= (DWORD
) - 1;
1990 row
.dwForwardMetric5
= (DWORD
) - 1;
1995 // check to make sure we don't already have a route
1997 if ( HaveRoute( &rowExtant
, inet_addr( kLLNetworkAddr
), 0 ) )
2000 // set the age to 0 so that we can do a memcmp.
2002 rowExtant
.dwForwardAge
= 0;
2005 // check to see if this route is the same as our route
2007 if (memcmp(&row
, &rowExtant
, sizeof(row
)) != 0)
2010 // if it isn't then delete this entry
2012 DeleteIpForwardEntry(&rowExtant
);
2017 // else it is, so we don't want to create another route
2023 if (addRoute
&& row
.dwForwardNextHop
)
2025 err
= CreateIpForwardEntry(&row
);
2036 //===========================================================================================================================
2037 // GetRouteDestination
2038 //===========================================================================================================================
2041 GetRouteDestination(DWORD
* ifIndex
, DWORD
* address
)
2044 IP_ADAPTER_INFO
* pAdapterInfo
= NULL
;
2045 IP_ADAPTER_INFO
* pAdapter
= NULL
;
2047 mDNSBool done
= mDNSfalse
;
2051 // GetBestInterface will fail if there is no default gateway
2052 // configured. If that happens, we will just take the first
2053 // interface in the list. MSDN support says there is no surefire
2054 // way to manually determine what the best interface might
2055 // be for a particular network address.
2057 ia
.s_addr
= inet_addr(kLLNetworkAddr
);
2058 err
= GetBestInterface(*(IPAddr
*) &ia
, ifIndex
);
2066 // Make an initial call to GetAdaptersInfo to get
2067 // the necessary size into the bufLen variable
2069 err
= GetAdaptersInfo( NULL
, &bufLen
);
2070 require_action( err
== ERROR_BUFFER_OVERFLOW
, exit
, err
= kUnknownErr
);
2072 pAdapterInfo
= (IP_ADAPTER_INFO
*) malloc( bufLen
);
2073 require_action( pAdapterInfo
, exit
, err
= kNoMemoryErr
);
2075 err
= GetAdaptersInfo( pAdapterInfo
, &bufLen
);
2076 require_noerr( err
, exit
);
2078 pAdapter
= pAdapterInfo
;
2081 // <rdar://problem/3718122>
2082 // <rdar://problem/5652098>
2084 // Look for the Nortel VPN virtual interface, along with Juniper virtual interface.
2086 // If these interfaces are active (i.e., has a non-zero IP Address),
2087 // then we want to disable routing table modifications.
2091 if ( ( IsNortelVPN( pAdapter
) || IsJuniperVPN( pAdapter
) || IsCiscoVPN( pAdapter
) ) &&
2092 ( inet_addr( pAdapter
->IpAddressList
.IpAddress
.String
) != 0 ) )
2094 dlog( kDebugLevelTrace
, DEBUG_NAME
"disabling routing table management due to VPN incompatibility" );
2098 pAdapter
= pAdapter
->Next
;
2103 pAdapter
= pAdapterInfo
;
2108 // If we don't have an interface selected, choose the first one that is of type ethernet and
2109 // has a valid IP Address
2111 if ((pAdapter
->Type
== MIB_IF_TYPE_ETHERNET
) && ( IsValidAddress( pAdapter
->IpAddressList
.IpAddress
.String
) ) && (!(*ifIndex
) || (pAdapter
->Index
== (*ifIndex
))))
2113 *address
= inet_addr( pAdapter
->IpAddressList
.IpAddress
.String
);
2114 *ifIndex
= pAdapter
->Index
;
2119 pAdapter
= pAdapter
->Next
;
2122 // If we found the right interface, or we weren't trying to find a specific interface then we're done
2124 if ( !err
|| !( *ifIndex
) )
2129 // Otherwise, try again by wildcarding the interface
2139 if ( pAdapterInfo
!= NULL
)
2141 free( pAdapterInfo
);
2149 IsNortelVPN( IP_ADAPTER_INFO
* pAdapter
)
2151 return ((pAdapter
->Type
== MIB_IF_TYPE_ETHERNET
) &&
2152 (pAdapter
->AddressLength
== 6) &&
2153 (pAdapter
->Address
[0] == 0x44) &&
2154 (pAdapter
->Address
[1] == 0x45) &&
2155 (pAdapter
->Address
[2] == 0x53) &&
2156 (pAdapter
->Address
[3] == 0x54) &&
2157 (pAdapter
->Address
[4] == 0x42) &&
2158 (pAdapter
->Address
[5] == 0x00)) ? true : false;
2163 IsJuniperVPN( IP_ADAPTER_INFO
* pAdapter
)
2165 return ( strnistr( pAdapter
->Description
, "Juniper", sizeof( pAdapter
->Description
) ) != NULL
) ? true : false;
2170 IsCiscoVPN( IP_ADAPTER_INFO
* pAdapter
)
2172 return ((pAdapter
->Type
== MIB_IF_TYPE_ETHERNET
) &&
2173 (pAdapter
->AddressLength
== 6) &&
2174 (pAdapter
->Address
[0] == 0x00) &&
2175 (pAdapter
->Address
[1] == 0x05) &&
2176 (pAdapter
->Address
[2] == 0x9a) &&
2177 (pAdapter
->Address
[3] == 0x3c) &&
2178 (pAdapter
->Address
[4] == 0x7a) &&
2179 (pAdapter
->Address
[5] == 0x00)) ? true : false;
2184 strnistr( const char * string
, const char * subString
, size_t max
)
2186 size_t subStringLen
;
2192 if ( ( string
== NULL
) || ( subString
== NULL
) )
2197 stringLen
= ( max
> strlen( string
) ) ? strlen( string
) : max
;
2199 if ( stringLen
== 0 )
2204 subStringLen
= strlen( subString
);
2206 if ( subStringLen
== 0 )
2211 if ( subStringLen
> stringLen
)
2216 maxOffset
= stringLen
- subStringLen
;
2219 for ( offset
= 0; offset
<= maxOffset
; offset
++ )
2221 if ( _strnicmp( pPos
, subString
, subStringLen
) == 0 )