]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSWindows/SystemService/Service.c
mDNSResponder-214.tar.gz
[apple/mdnsresponder.git] / mDNSWindows / SystemService / Service.c
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
4 *
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
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
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.
16
17 Change History (most recent first):
18
19 $Log: Service.c,v $
20 Revision 1.49 2009/07/17 19:59:46 herscher
21 <rdar://problem/7062660> Update the womp settings for each network adapter immediately preceding the call to mDNSCoreMachineSleep().
22
23 Revision 1.48 2009/07/09 21:34:14 herscher
24 <rdar://problem/3775717> SDK: Port mDNSNetMonitor to Windows. Refactor the system service slightly by removing the main() function from Service.c so that mDNSNetMonitor can link to functions defined in Service.c
25
26 Revision 1.47 2009/07/07 21:35:06 herscher
27 <rdar://problem/6713286> windows platform changes to support use as sleep proxy client
28
29 Revision 1.46 2009/06/05 18:28:24 herscher
30 <rdar://problem/6125087> mDNSResponder should be able to identify VPN adapters generically
31 <rdar://problem/6885843> WIN7: Bonjour removes the default gateway entry and thereby breaks network connectivity
32
33 Revision 1.45 2009/04/30 20:07:51 mcguire
34 <rdar://problem/6822674> Support multiple UDSs from launchd
35
36 Revision 1.44 2009/03/30 20:41:36 herscher
37 <rdar://problem/5925472> Current Bonjour code does not compile on Windows
38 <rdar://problem/6330821> Bonjour for Windows incompatible w/Juniper Network Connect. Do a substring search for "Juniper" in the description field
39 of the network adapter.
40 <rdar://problem/6122028> Bonjour for Windows incompatible w/Cisco AnyConnect VPN Client
41 <rdar://problem/5652098> Bonjour for Windows incompatible w/Juniper Network Connect. Update the adapter name per info received from Juniper
42 <rdar://problem/5781566> Core: Default Gateway set to 0.0.0.0 on Vista causes ARP flood
43 <rdar://problem/5991983> Change the registry values from Apple Computer, Inc. to Apple Inc.
44 <rdar://problem/5301328> wchar/sizeof mismatch in CheckFirewall()
45
46 Revision 1.43 2009/01/13 05:31:35 mkrochma
47 <rdar://problem/6491367> Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy
48
49 Revision 1.42 2007/02/14 01:58:19 cheshire
50 <rdar://problem/4995831> Don't delete Unix Domain Socket on exit if we didn't create it on startup
51
52 Revision 1.41 2007/02/06 19:06:49 cheshire
53 <rdar://problem/3956518> Need to go native with launchd
54
55 Revision 1.40 2007/01/05 05:46:08 cheshire
56 Add mDNS *const m parameter to udsserver_handle_configchange()
57
58 Revision 1.39 2006/08/14 23:26:07 cheshire
59 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
60
61 Revision 1.38 2005/10/05 20:55:15 herscher
62 <rdar://problem/4096464> Don't call SetLLRoute on loopback interface
63
64 Revision 1.37 2005/10/05 18:05:28 herscher
65 <rdar://problem/4192011> Save Wide-Area preferences in a different spot in the registry so they don't get removed when doing an update install.
66
67 Revision 1.36 2005/09/11 22:12:42 herscher
68 <rdar://problem/4247793> Remove dependency on WMI. Ensure that the Windows firewall is turned on before trying to configure it.
69
70 Revision 1.35 2005/06/30 18:29:49 shersche
71 <rdar://problem/4090059> Don't overwrite the localized service description text
72
73 Revision 1.34 2005/04/22 07:34:23 shersche
74 Check an interface's address and make sure it's valid before using it to set link-local routes.
75
76 Revision 1.33 2005/04/13 17:48:23 shersche
77 <rdar://problem/4079667> Make sure there is only one default route for link-local addresses.
78
79 Revision 1.32 2005/04/06 01:32:05 shersche
80 Remove default route for link-local addressing when another interface comes up with a routable IPv4 address
81
82 Revision 1.31 2005/04/06 01:00:11 shersche
83 <rdar://problem/4080127> GetFullPathName() should be passed the number of TCHARs in the path buffer, not the size in bytes of the path buffer.
84
85 Revision 1.30 2005/04/06 00:52:43 shersche
86 <rdar://problem/4079667> Only add default route if there are no other routable IPv4 addresses on any of the other interfaces. More work needs to be done to correctly configure the routing table when multiple interfaces are extant and none of them have routable IPv4 addresses.
87
88 Revision 1.29 2005/03/06 05:21:56 shersche
89 <rdar://problem/4037635> Fix corrupt UTF-8 name when non-ASCII system name used, enabled unicode support
90
91 Revision 1.28 2005/03/03 02:27:24 shersche
92 Include the RegNames.h header file for names of registry keys
93
94 Revision 1.27 2005/03/02 20:12:59 shersche
95 Update name
96
97 Revision 1.26 2005/02/15 08:00:27 shersche
98 <rdar://problem/4007151> Update name
99
100 Revision 1.25 2005/02/10 22:35:36 cheshire
101 <rdar://problem/3727944> Update name
102
103 Revision 1.24 2005/01/27 20:02:43 cheshire
104 udsSupportRemoveFDFromEventLoop() needs to close the SocketRef as well
105
106 Revision 1.23 2005/01/25 08:14:15 shersche
107 Change CacheRecord to CacheEntity
108
109 Revision 1.22 2004/12/10 13:18:40 cheshire
110 Create no-op function RecordUpdatedNiceLabel(), required by uds_daemon.c
111
112 Revision 1.21 2004/11/10 04:03:41 shersche
113 Remove SharedAccess dependency. This causes problems on XP SP1, and isn't necessary for XP SP2 because we already are dependent on WMI, which itself is dependent on SharedAccess.
114
115 Revision 1.20 2004/10/14 21:44:05 shersche
116 <rdar://problem/3838237> Fix a race condition between the socket thread and the main processing thread that resulted in the socket thread accessing a previously deleted Win32EventSource object.
117 Bug #: 3838237
118
119 Revision 1.19 2004/10/12 17:59:55 shersche
120 <rdar://problem/3718122> Disable routing table modifications when Nortel VPN adapter is active
121 Bug #: 3718122
122
123 Revision 1.18 2004/10/11 21:57:50 shersche
124 <rdar://problem/3832450> The SharedAccess service dependency causes a circular dependency on Windows Server 2003. Only add the SharedAccess service dependency if running on XP. All other platforms do not manipulate the firewall and thus are not dependent on it.
125 Bug #: 3832450
126
127 Revision 1.17 2004/09/17 01:08:58 cheshire
128 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
129 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
130 declared in that file are ONLY appropriate to single-address-space embedded applications.
131 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
132
133 Revision 1.16 2004/09/16 18:49:34 shersche
134 Remove the XP SP2 check before attempting to manage the firewall. There is a race condition in the SP2 updater such that upon first reboot after the upgrade, mDNSResponder might not know that it is running under SP2 yet. This necessitates a second reboot before the firewall is managed. Removing the check will cause mDNSResponder to try and manage the firewall everytime it boots up, if and only if it hasn't managed the firewall a previous time.
135
136 Revision 1.15 2004/09/15 17:13:33 shersche
137 Change Firewall name
138
139 Revision 1.14 2004/09/15 09:37:25 shersche
140 Add SharedAccess to dependency list, call CheckFirewall after sending status back to SCM
141
142 Revision 1.13 2004/09/13 07:35:10 shersche
143 <rdar://problem/3762235> Add mDNSResponder to Windows Firewall application list if SP2 is detected and app hasn't been added before
144 Bug #: 3762235
145
146 Revision 1.12 2004/09/11 21:18:32 shersche
147 <rdar://problem/3779502> Add route to ARP everything when a 169.254.x.x address is selected
148 Bug #: 3779502
149
150 Revision 1.11 2004/09/11 05:39:19 shersche
151 <rdar://problem/3780203> Detect power managment state changes, calling mDNSCoreMachineSleep(m, true) on sleep, and mDNSCoreMachineSleep(m, false) on resume
152 Bug #: 3780203
153
154 Revision 1.10 2004/08/16 21:45:24 shersche
155 Use the full pathname of executable when calling CreateService()
156 Submitted by: prepin@zetron.com
157
158 Revision 1.9 2004/08/11 01:59:41 cheshire
159 Remove "mDNS *globalInstance" parameter from udsserver_init()
160
161 Revision 1.8 2004/08/05 05:40:05 shersche
162 <rdar://problem/3751566> Only invoke SetConsoleCtrlHandler when running directly from command line.
163 <rdar://problem/3751481> Invoke udsserver_handle_configchange() when the computer description changes
164 Bug #: 3751481, 3751566
165
166 Revision 1.7 2004/07/26 05:35:07 shersche
167 ignore non-enet interfaces when setting up link-local routing
168
169 Revision 1.6 2004/07/20 06:48:26 shersche
170 <rdar://problem/3718122> Allow registry entries to dictate whether to manage link local routing
171 Bug #: 3718122
172
173 Revision 1.5 2004/07/09 19:08:07 shersche
174 <rdar://problem/3713762> ServiceSetupEventLogging() errors are handled gracefully
175 Bug #: 3713762
176
177 Revision 1.4 2004/06/24 20:58:15 shersche
178 Fix compiler error in Release build
179 Submitted by: herscher
180
181 Revision 1.3 2004/06/24 15:28:53 shersche
182 Automatically setup routes to link-local addresses upon interface list change events.
183 Submitted by: herscher
184
185 Revision 1.2 2004/06/23 16:56:00 shersche
186 <rdar://problem/3697326> locked call to udsserver_idle().
187 Bug #: 3697326
188 Submitted by: herscher
189
190 Revision 1.1 2004/06/18 04:16:41 rpantos
191 Move up one level.
192
193 Revision 1.1 2004/01/30 02:58:39 bradley
194 mDNSResponder Windows Service. Provides global Bonjour support with an IPC interface.
195
196 */
197
198 #include <stdio.h>
199 #include <stdlib.h>
200 #include <stdarg.h>
201 #include <stddef.h>
202
203
204 #include "CommonServices.h"
205 #include "DebugServices.h"
206 #include "RegNames.h"
207
208 #include "uds_daemon.h"
209 #include "GenLinkedList.h"
210 #include "Service.h"
211
212 #include "Resource.h"
213
214 #include "mDNSEmbeddedAPI.h"
215 #include "mDNSWin32.h"
216
217 #include "Firewall.h"
218
219 #if( !TARGET_OS_WINDOWS_CE )
220 #include <mswsock.h>
221 #include <process.h>
222 #include <ipExport.h>
223 #include <ws2def.h>
224 #include <ws2ipdef.h>
225 #include <iphlpapi.h>
226 #include <netioapi.h>
227 #include <iptypes.h>
228 #include <powrprof.h>
229 #endif
230
231 #ifndef HeapEnableTerminationOnCorruption
232 # define HeapEnableTerminationOnCorruption (HEAP_INFORMATION_CLASS)1
233 #endif
234
235 #if 0
236 #pragma mark == Constants ==
237 #endif
238
239 //===========================================================================================================================
240 // Constants
241 //===========================================================================================================================
242
243 #define DEBUG_NAME "[Server] "
244 #define kServiceFirewallName L"Bonjour"
245 #define kServiceDependencies TEXT("Tcpip\0\0")
246 #define kDNSServiceCacheEntryCountDefault 512
247 #define kRetryFirewallPeriod 30 * 1000
248 #define kDefValueSize MAX_PATH + 1
249 #define kZeroIndex 0
250 #define kDefaultRouteMetric 399
251
252 #define RR_CACHE_SIZE 500
253 static CacheEntity gRRCache[RR_CACHE_SIZE];
254 #if 0
255 #pragma mark == Structures ==
256 #endif
257
258 //===========================================================================================================================
259 // Structures
260 //===========================================================================================================================
261 //---------------------------------------------------------------------------------------------------------------------------
262 /*! @typedef EventSourceFlags
263
264 @abstract Session flags.
265
266 @constant EventSourceFlagsNone No flags.
267 @constant EventSourceFlagsThreadDone Thread is no longer active.
268 @constant EventSourceFlagsNoClose Do not close the session when the thread exits.
269 @constant EventSourceFinalized Finalize has been called for this session
270 */
271
272 typedef uint32_t EventSourceFlags;
273
274 #define EventSourceFlagsNone 0
275 #define EventSourceFlagsThreadDone ( 1 << 2 )
276 #define EventSourceFlagsNoClose ( 1 << 3 )
277 #define EventSourceFinalized ( 1 << 4 )
278
279
280 typedef struct Win32EventSource
281 {
282 EventSourceFlags flags;
283 HANDLE threadHandle;
284 unsigned threadID;
285 HANDLE socketEvent;
286 HANDLE closeEvent;
287 udsEventCallback callback;
288 void * context;
289 DWORD waitCount;
290 HANDLE waitList[2];
291 SOCKET sock;
292 struct Win32EventSource * next;
293 } Win32EventSource;
294
295
296 #if 0
297 #pragma mark == Prototypes ==
298 #endif
299
300 //===========================================================================================================================
301 // Prototypes
302 //===========================================================================================================================
303 static void Usage( void );
304 static BOOL WINAPI ConsoleControlHandler( DWORD inControlEvent );
305 static OSStatus InstallService( LPCTSTR inName, LPCTSTR inDisplayName, LPCTSTR inDescription, LPCTSTR inPath );
306 static OSStatus RemoveService( LPCTSTR inName );
307 static OSStatus SetServiceParameters();
308 static OSStatus GetServiceParameters();
309 static OSStatus CheckFirewall();
310 static OSStatus SetServiceInfo( SC_HANDLE inSCM, LPCTSTR inServiceName, LPCTSTR inDescription );
311 static void ReportStatus( int inType, const char *inFormat, ... );
312
313 static void WINAPI ServiceMain( DWORD argc, LPTSTR argv[] );
314 static OSStatus ServiceSetupEventLogging( void );
315 static DWORD WINAPI ServiceControlHandler( DWORD inControl, DWORD inEventType, LPVOID inEventData, LPVOID inContext );
316
317 static OSStatus ServiceRun( int argc, LPTSTR argv[] );
318 static void ServiceStop( void );
319
320 static OSStatus ServiceSpecificInitialize( int argc, LPTSTR argv[] );
321 static OSStatus ServiceSpecificRun( int argc, LPTSTR argv[] );
322 static OSStatus ServiceSpecificStop( void );
323 static void ServiceSpecificFinalize( int argc, LPTSTR argv[] );
324 static mStatus EventSourceFinalize(Win32EventSource * source);
325 static void EventSourceLock();
326 static void EventSourceUnlock();
327 static mDNSs32 udsIdle(mDNS * const inMDNS, mDNSs32 interval);
328 static void CoreCallback(mDNS * const inMDNS, mStatus result);
329 static void HostDescriptionChanged(mDNS * const inMDNS);
330 static mDNSu8 SystemWakeForNetworkAccess( LARGE_INTEGER * timeout );
331 static OSStatus GetRouteDestination(DWORD * ifIndex, DWORD * address);
332 static OSStatus SetLLRoute( mDNS * const inMDNS );
333 static bool HaveRoute( PMIB_IPFORWARDROW rowExtant, unsigned long addr, unsigned long metric );
334 static bool IsValidAddress( const char * addr );
335 static bool IsNortelVPN( IP_ADAPTER_INFO * pAdapter );
336 static bool IsJuniperVPN( IP_ADAPTER_INFO * pAdapter );
337 static bool IsCiscoVPN( IP_ADAPTER_INFO * pAdapter );
338 static const char * strnistr( const char * string, const char * subString, size_t max );
339
340 #if defined(UNICODE)
341 # define StrLen(X) wcslen(X)
342 # define StrCmp(X,Y) wcscmp(X,Y)
343 #else
344 # define StrLen(X) strlen(X)
345 # define StrCmp(X,Y) strcmp(X,Y)
346 #endif
347
348
349 #define kLLNetworkAddr "169.254.0.0"
350 #define kLLNetworkAddrMask "255.255.0.0"
351
352
353 #include "mDNSEmbeddedAPI.h"
354
355 #if 0
356 #pragma mark == Globals ==
357 #endif
358
359 //===========================================================================================================================
360 // Globals
361 //===========================================================================================================================
362 #define gMDNSRecord mDNSStorage
363 DEBUG_LOCAL mDNS_PlatformSupport gPlatformStorage;
364 DEBUG_LOCAL BOOL gServiceQuietMode = FALSE;
365 DEBUG_LOCAL SERVICE_TABLE_ENTRY gServiceDispatchTable[] =
366 {
367 { kServiceName, ServiceMain },
368 { NULL, NULL }
369 };
370 DEBUG_LOCAL SERVICE_STATUS gServiceStatus;
371 DEBUG_LOCAL SERVICE_STATUS_HANDLE gServiceStatusHandle = NULL;
372 DEBUG_LOCAL HANDLE gServiceEventSource = NULL;
373 DEBUG_LOCAL bool gServiceAllowRemote = false;
374 DEBUG_LOCAL int gServiceCacheEntryCount = 0; // 0 means to use the DNS-SD default.
375 DEBUG_LOCAL bool gServiceManageLLRouting = true;
376 DEBUG_LOCAL int gWaitCount = 0;
377 DEBUG_LOCAL HANDLE * gWaitList = NULL;
378 DEBUG_LOCAL HANDLE gStopEvent = NULL;
379 DEBUG_LOCAL HANDLE gSPSWakeupEvent = NULL;
380 DEBUG_LOCAL HANDLE gSPSSleepEvent = NULL;
381 DEBUG_LOCAL CRITICAL_SECTION gEventSourceLock;
382 DEBUG_LOCAL GenLinkedList gEventSources;
383 DEBUG_LOCAL BOOL gRetryFirewall = FALSE;
384 DEBUG_LOCAL DWORD gOSMajorVersion;
385 DEBUG_LOCAL DWORD gOSMinorVersion;
386
387 typedef DWORD ( WINAPI * GetIpInterfaceEntryFunctionPtr )( PMIB_IPINTERFACE_ROW );
388 mDNSlocal HMODULE gIPHelperLibraryInstance = NULL;
389 mDNSlocal GetIpInterfaceEntryFunctionPtr gGetIpInterfaceEntryFunctionPtr = NULL;
390
391
392 #if 0
393 #pragma mark -
394 #endif
395
396 //===========================================================================================================================
397 // Main
398 //===========================================================================================================================
399 int Main( int argc, LPTSTR argv[] )
400 {
401 OSStatus err;
402 BOOL ok;
403 BOOL start;
404 int i;
405
406 HeapSetInformation( NULL, HeapEnableTerminationOnCorruption, NULL, 0 );
407
408 debug_initialize( kDebugOutputTypeMetaConsole );
409 debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelVerbose );
410
411 // Default to automatically starting the service dispatcher if no extra arguments are specified.
412
413 start = ( argc <= 1 );
414
415 // Parse arguments.
416
417 for( i = 1; i < argc; ++i )
418 {
419 if( StrCmp( argv[ i ], TEXT("-install") ) == 0 ) // Install
420 {
421 TCHAR desc[ 256 ];
422
423 desc[ 0 ] = 0;
424 LoadString( GetModuleHandle( NULL ), IDS_SERVICE_DESCRIPTION, desc, sizeof( desc ) );
425 err = InstallService( kServiceName, kServiceName, desc, argv[0] );
426 if( err )
427 {
428 ReportStatus( EVENTLOG_ERROR_TYPE, "install service failed (%d)\n", err );
429 goto exit;
430 }
431 }
432 else if( StrCmp( argv[ i ], TEXT("-remove") ) == 0 ) // Remove
433 {
434 err = RemoveService( kServiceName );
435 if( err )
436 {
437 ReportStatus( EVENTLOG_ERROR_TYPE, "remove service failed (%d)\n", err );
438 goto exit;
439 }
440 }
441 else if( StrCmp( argv[ i ], TEXT("-start") ) == 0 ) // Start
442 {
443 start = TRUE;
444 }
445 else if( StrCmp( argv[ i ], TEXT("-server") ) == 0 ) // Server
446 {
447 err = RunDirect( argc, argv );
448 if( err )
449 {
450 ReportStatus( EVENTLOG_ERROR_TYPE, "run service directly failed (%d)\n", err );
451 }
452 goto exit;
453 }
454 else if( StrCmp( argv[ i ], TEXT("-q") ) == 0 ) // Quiet Mode (toggle)
455 {
456 gServiceQuietMode = !gServiceQuietMode;
457 }
458 else if( ( StrCmp( argv[ i ], TEXT("-help") ) == 0 ) || // Help
459 ( StrCmp( argv[ i ], TEXT("-h") ) == 0 ) )
460 {
461 Usage();
462 err = 0;
463 break;
464 }
465 else
466 {
467 Usage();
468 err = kParamErr;
469 break;
470 }
471 }
472
473 // Start the service dispatcher if requested. This does not return until all services have terminated. If any
474 // global initialization is needed, it should be done before starting the service dispatcher, but only if it
475 // will take less than 30 seconds. Otherwise, use a separate thread for it and start the dispatcher immediately.
476
477 if( start )
478 {
479 ok = StartServiceCtrlDispatcher( gServiceDispatchTable );
480 err = translate_errno( ok, (OSStatus) GetLastError(), kInUseErr );
481 if( err != kNoErr )
482 {
483 ReportStatus( EVENTLOG_ERROR_TYPE, "start service dispatcher failed (%d)\n", err );
484 goto exit;
485 }
486 }
487 err = 0;
488
489 exit:
490 dlog( kDebugLevelTrace, DEBUG_NAME "exited (%d %m)\n", err, err );
491 return( (int) err );
492 }
493
494 //===========================================================================================================================
495 // Usage
496 //===========================================================================================================================
497
498 static void Usage( void )
499 {
500 fprintf( stderr, "\n" );
501 fprintf( stderr, "mDNSResponder 1.0d1\n" );
502 fprintf( stderr, "\n" );
503 fprintf( stderr, " <no args> Runs the service normally\n" );
504 fprintf( stderr, " -install Creates the service and starts it\n" );
505 fprintf( stderr, " -remove Stops the service and deletes it\n" );
506 fprintf( stderr, " -start Starts the service dispatcher after processing all other arguments\n" );
507 fprintf( stderr, " -server Runs the service directly as a server (for debugging)\n" );
508 fprintf( stderr, " -q Toggles Quiet Mode (no events or output)\n" );
509 fprintf( stderr, " -remote Allow remote connections\n" );
510 fprintf( stderr, " -cache n Number of mDNS cache entries (defaults to %d)\n", kDNSServiceCacheEntryCountDefault );
511 fprintf( stderr, " -h[elp] Display Help/Usage\n" );
512 fprintf( stderr, "\n" );
513 }
514
515 //===========================================================================================================================
516 // ConsoleControlHandler
517 //===========================================================================================================================
518
519 static BOOL WINAPI ConsoleControlHandler( DWORD inControlEvent )
520 {
521 BOOL handled;
522 OSStatus err;
523
524 handled = FALSE;
525 switch( inControlEvent )
526 {
527 case CTRL_C_EVENT:
528 case CTRL_BREAK_EVENT:
529 case CTRL_CLOSE_EVENT:
530 case CTRL_LOGOFF_EVENT:
531 case CTRL_SHUTDOWN_EVENT:
532 err = ServiceSpecificStop();
533 require_noerr( err, exit );
534
535 handled = TRUE;
536 break;
537
538 default:
539 break;
540 }
541
542 exit:
543 return( handled );
544 }
545
546 //===========================================================================================================================
547 // InstallService
548 //===========================================================================================================================
549
550 static OSStatus InstallService( LPCTSTR inName, LPCTSTR inDisplayName, LPCTSTR inDescription, LPCTSTR inPath )
551 {
552 OSStatus err;
553 SC_HANDLE scm;
554 SC_HANDLE service;
555 BOOL ok;
556 TCHAR fullPath[ MAX_PATH ];
557 TCHAR * namePtr;
558 DWORD size;
559
560 scm = NULL;
561 service = NULL;
562
563 // Get a full path to the executable since a relative path may have been specified.
564
565 size = GetFullPathName( inPath, MAX_PATH, fullPath, &namePtr );
566 err = translate_errno( size > 0, (OSStatus) GetLastError(), kPathErr );
567 require_noerr( err, exit );
568
569 // Create the service and start it.
570
571 scm = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
572 err = translate_errno( scm, (OSStatus) GetLastError(), kOpenErr );
573 require_noerr( err, exit );
574
575 service = CreateService( scm, inName, inDisplayName, SERVICE_ALL_ACCESS, SERVICE_WIN32_SHARE_PROCESS,
576 SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, fullPath, NULL, NULL, kServiceDependencies,
577 NULL, NULL );
578 err = translate_errno( service, (OSStatus) GetLastError(), kDuplicateErr );
579 require_noerr( err, exit );
580
581 err = SetServiceParameters();
582 check_noerr( err );
583
584 if( inDescription )
585 {
586 err = SetServiceInfo( scm, inName, inDescription );
587 check_noerr( err );
588 }
589
590 ok = StartService( service, 0, NULL );
591 err = translate_errno( ok, (OSStatus) GetLastError(), kInUseErr );
592 require_noerr( err, exit );
593
594 ReportStatus( EVENTLOG_SUCCESS, "installed service \"%s\"/\"%s\" at \"%s\"\n", inName, inDisplayName, inPath );
595 err = kNoErr;
596
597 exit:
598 if( service )
599 {
600 CloseServiceHandle( service );
601 }
602 if( scm )
603 {
604 CloseServiceHandle( scm );
605 }
606 return( err );
607 }
608
609 //===========================================================================================================================
610 // RemoveService
611 //===========================================================================================================================
612
613 static OSStatus RemoveService( LPCTSTR inName )
614 {
615 OSStatus err;
616 SC_HANDLE scm;
617 SC_HANDLE service;
618 BOOL ok;
619 SERVICE_STATUS status;
620
621 scm = NULL;
622 service = NULL;
623
624 // Open a connection to the service.
625
626 scm = OpenSCManager( 0, 0, SC_MANAGER_ALL_ACCESS );
627 err = translate_errno( scm, (OSStatus) GetLastError(), kOpenErr );
628 require_noerr( err, exit );
629
630 service = OpenService( scm, inName, SERVICE_STOP | SERVICE_QUERY_STATUS | DELETE );
631 err = translate_errno( service, (OSStatus) GetLastError(), kNotFoundErr );
632 require_noerr( err, exit );
633
634 // Stop the service, if it is not already stopped, then delete it.
635
636 ok = QueryServiceStatus( service, &status );
637 err = translate_errno( ok, (OSStatus) GetLastError(), kAuthenticationErr );
638 require_noerr( err, exit );
639
640 if( status.dwCurrentState != SERVICE_STOPPED )
641 {
642 ok = ControlService( service, SERVICE_CONTROL_STOP, &status );
643 check_translated_errno( ok, (OSStatus) GetLastError(), kAuthenticationErr );
644 }
645
646 ok = DeleteService( service );
647 err = translate_errno( ok, (OSStatus) GetLastError(), kDeletedErr );
648 require_noerr( err, exit );
649
650 ReportStatus( EVENTLOG_SUCCESS, "Removed service \"%s\"\n", inName );
651 err = ERROR_SUCCESS;
652
653 exit:
654 if( service )
655 {
656 CloseServiceHandle( service );
657 }
658 if( scm )
659 {
660 CloseServiceHandle( scm );
661 }
662 return( err );
663 }
664
665
666
667 //===========================================================================================================================
668 // SetServiceParameters
669 //===========================================================================================================================
670
671 static OSStatus SetServiceParameters()
672 {
673 DWORD value;
674 DWORD valueLen = sizeof(DWORD);
675 DWORD type;
676 OSStatus err;
677 HKEY key;
678
679 key = NULL;
680
681 //
682 // Add/Open Parameters section under service entry in registry
683 //
684 err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode, &key );
685 require_noerr( err, exit );
686
687 //
688 // If the value isn't already there, then we create it
689 //
690 err = RegQueryValueEx(key, kServiceManageLLRouting, 0, &type, (LPBYTE) &value, &valueLen);
691
692 if (err != ERROR_SUCCESS)
693 {
694 value = 1;
695
696 err = RegSetValueEx( key, kServiceManageLLRouting, 0, REG_DWORD, (const LPBYTE) &value, sizeof(DWORD) );
697 require_noerr( err, exit );
698 }
699
700 exit:
701
702 if ( key )
703 {
704 RegCloseKey( key );
705 }
706
707 return( err );
708 }
709
710
711
712 //===========================================================================================================================
713 // GetServiceParameters
714 //===========================================================================================================================
715
716 static OSStatus GetServiceParameters()
717 {
718 DWORD value;
719 DWORD valueLen;
720 DWORD type;
721 OSStatus err;
722 HKEY key;
723
724 key = NULL;
725
726 //
727 // Add/Open Parameters section under service entry in registry
728 //
729 err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode, &key );
730 require_noerr( err, exit );
731
732 valueLen = sizeof(DWORD);
733 err = RegQueryValueEx(key, kServiceManageLLRouting, 0, &type, (LPBYTE) &value, &valueLen);
734 if (err == ERROR_SUCCESS)
735 {
736 gServiceManageLLRouting = (value) ? true : false;
737 }
738
739 valueLen = sizeof(DWORD);
740 err = RegQueryValueEx(key, kServiceCacheEntryCount, 0, &type, (LPBYTE) &value, &valueLen);
741 if (err == ERROR_SUCCESS)
742 {
743 gServiceCacheEntryCount = value;
744 }
745
746 exit:
747
748 if ( key )
749 {
750 RegCloseKey( key );
751 }
752
753 return( err );
754 }
755
756
757 //===========================================================================================================================
758 // CheckFirewall
759 //===========================================================================================================================
760
761 static OSStatus CheckFirewall()
762 {
763 DWORD value;
764 DWORD valueLen;
765 DWORD type;
766 ENUM_SERVICE_STATUS * lpService = NULL;
767 SC_HANDLE sc = NULL;
768 HKEY key = NULL;
769 BOOL ok;
770 DWORD bytesNeeded = 0;
771 DWORD srvCount;
772 DWORD resumeHandle = 0;
773 DWORD srvType;
774 DWORD srvState;
775 DWORD dwBytes = 0;
776 DWORD i;
777 BOOL isRunning = FALSE;
778 OSStatus err = kUnknownErr;
779
780 // Check to see if the firewall service is running. If it isn't, then
781 // we want to return immediately
782
783 sc = OpenSCManager( NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE );
784 err = translate_errno( sc, GetLastError(), kUnknownErr );
785 require_noerr( err, exit );
786
787 srvType = SERVICE_WIN32;
788 srvState = SERVICE_STATE_ALL;
789
790 for ( ;; )
791 {
792 // Call EnumServicesStatus using the handle returned by OpenSCManager
793
794 ok = EnumServicesStatus ( sc, srvType, srvState, lpService, dwBytes, &bytesNeeded, &srvCount, &resumeHandle );
795
796 if ( ok || ( GetLastError() != ERROR_MORE_DATA ) )
797 {
798 break;
799 }
800
801 if ( lpService )
802 {
803 free( lpService );
804 }
805
806 dwBytes = bytesNeeded;
807
808 lpService = ( ENUM_SERVICE_STATUS* ) malloc( dwBytes );
809 require_action( lpService, exit, err = mStatus_NoMemoryErr );
810 }
811
812 err = translate_errno( ok, GetLastError(), kUnknownErr );
813 require_noerr( err, exit );
814
815 for ( i = 0; i < srvCount; i++ )
816 {
817 if ( wcscmp( lpService[i].lpServiceName, L"SharedAccess" ) == 0 )
818 {
819 if ( lpService[i].ServiceStatus.dwCurrentState == SERVICE_RUNNING )
820 {
821 isRunning = TRUE;
822 }
823
824 break;
825 }
826 }
827
828 require_action( isRunning, exit, err = kUnknownErr );
829
830 // Check to see if we've managed the firewall.
831 // This package might have been installed, then
832 // the OS was upgraded to SP2 or above. If that's
833 // the case, then we need to manipulate the firewall
834 // so networking works correctly.
835
836 err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode, &key );
837 require_noerr( err, exit );
838
839 valueLen = sizeof(DWORD);
840 err = RegQueryValueEx(key, kServiceManageFirewall, 0, &type, (LPBYTE) &value, &valueLen);
841
842 if ((err != ERROR_SUCCESS) || (value == 0))
843 {
844 wchar_t fullPath[ MAX_PATH ];
845 DWORD size;
846
847 // Get a full path to the executable
848
849 size = GetModuleFileNameW( NULL, fullPath, MAX_PATH );
850 err = translate_errno( size > 0, (OSStatus) GetLastError(), kPathErr );
851 require_noerr( err, exit );
852
853 err = mDNSAddToFirewall(fullPath, kServiceFirewallName);
854 require_noerr( err, exit );
855
856 value = 1;
857 err = RegSetValueEx( key, kServiceManageFirewall, 0, REG_DWORD, (const LPBYTE) &value, sizeof( DWORD ) );
858 require_noerr( err, exit );
859 }
860
861 exit:
862
863 if ( key )
864 {
865 RegCloseKey( key );
866 }
867
868 if ( lpService )
869 {
870 free( lpService );
871 }
872
873 if ( sc )
874 {
875 CloseServiceHandle ( sc );
876 }
877
878 return( err );
879 }
880
881
882
883 //===========================================================================================================================
884 // SetServiceInfo
885 //===========================================================================================================================
886
887 static OSStatus SetServiceInfo( SC_HANDLE inSCM, LPCTSTR inServiceName, LPCTSTR inDescription )
888 {
889 OSStatus err;
890 SC_LOCK lock;
891 SC_HANDLE service;
892 SERVICE_DESCRIPTION description;
893 SERVICE_FAILURE_ACTIONS actions;
894 SC_ACTION action;
895 BOOL ok;
896
897 check( inServiceName );
898 check( inDescription );
899
900 lock = NULL;
901 service = NULL;
902
903 // Open the database (if not provided) and lock it to prevent other access while re-configuring.
904
905 if( !inSCM )
906 {
907 inSCM = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
908 err = translate_errno( inSCM, (OSStatus) GetLastError(), kOpenErr );
909 require_noerr( err, exit );
910 }
911
912 lock = LockServiceDatabase( inSCM );
913 err = translate_errno( lock, (OSStatus) GetLastError(), kInUseErr );
914 require_noerr( err, exit );
915
916 // Open a handle to the service.
917
918 service = OpenService( inSCM, inServiceName, SERVICE_CHANGE_CONFIG|SERVICE_START );
919 err = translate_errno( service, (OSStatus) GetLastError(), kNotFoundErr );
920 require_noerr( err, exit );
921
922 // Change the description.
923
924 description.lpDescription = (LPTSTR) inDescription;
925 ok = ChangeServiceConfig2( service, SERVICE_CONFIG_DESCRIPTION, &description );
926 err = translate_errno( ok, (OSStatus) GetLastError(), kParamErr );
927 require_noerr( err, exit );
928
929 actions.dwResetPeriod = INFINITE;
930 actions.lpRebootMsg = NULL;
931 actions.lpCommand = NULL;
932 actions.cActions = 1;
933 actions.lpsaActions = &action;
934 action.Delay = 500;
935 action.Type = SC_ACTION_RESTART;
936
937 ok = ChangeServiceConfig2( service, SERVICE_CONFIG_FAILURE_ACTIONS, &actions );
938 err = translate_errno( ok, (OSStatus) GetLastError(), kParamErr );
939 require_noerr( err, exit );
940
941 err = ERROR_SUCCESS;
942
943 exit:
944 // Close the service and release the lock.
945
946 if( service )
947 {
948 CloseServiceHandle( service );
949 }
950 if( lock )
951 {
952 UnlockServiceDatabase( lock );
953 }
954 return( err );
955 }
956
957 //===========================================================================================================================
958 // ReportStatus
959 //===========================================================================================================================
960
961 static void ReportStatus( int inType, const char *inFormat, ... )
962 {
963 if( !gServiceQuietMode )
964 {
965 va_list args;
966
967 va_start( args, inFormat );
968 if( gServiceEventSource )
969 {
970 char s[ 1024 ];
971 BOOL ok;
972 const char * array[ 1 ];
973
974 vsprintf( s, inFormat, args );
975 array[ 0 ] = s;
976 ok = ReportEventA( gServiceEventSource, (WORD) inType, 0, 0x20000001L, NULL, 1, 0, array, NULL );
977 check_translated_errno( ok, GetLastError(), kUnknownErr );
978 }
979 else
980 {
981 int n;
982
983 n = vfprintf( stderr, inFormat, args );
984 check( n >= 0 );
985 }
986 va_end( args );
987 }
988 }
989
990 //===========================================================================================================================
991 // RunDirect
992 //===========================================================================================================================
993
994 int RunDirect( int argc, LPTSTR argv[] )
995 {
996 OSStatus err;
997 BOOL initialized;
998 BOOL ok;
999
1000 initialized = FALSE;
1001
1002 // Install a Console Control Handler to handle things like control-c signals.
1003
1004 ok = SetConsoleCtrlHandler( ConsoleControlHandler, TRUE );
1005 err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
1006 require_noerr( err, exit );
1007
1008 err = ServiceSpecificInitialize( argc, argv );
1009 require_noerr( err, exit );
1010 initialized = TRUE;
1011
1012 // Run the service. This does not return until the service quits or is stopped.
1013
1014 ReportStatus( EVENTLOG_SUCCESS, "Running \"%s\" service directly\n", kServiceName );
1015
1016 err = ServiceSpecificRun( argc, argv );
1017 require_noerr( err, exit );
1018
1019 // Clean up.
1020
1021 exit:
1022 if( initialized )
1023 {
1024 ServiceSpecificFinalize( argc, argv );
1025 }
1026 return( err );
1027 }
1028
1029 #if 0
1030 #pragma mark -
1031 #endif
1032
1033 //===========================================================================================================================
1034 // ServiceMain
1035 //===========================================================================================================================
1036
1037 static void WINAPI ServiceMain( DWORD argc, LPTSTR argv[] )
1038 {
1039 OSStatus err;
1040 BOOL ok;
1041
1042 err = ServiceSetupEventLogging();
1043 check_noerr( err );
1044
1045 err = GetServiceParameters();
1046 check_noerr( err );
1047
1048 // Initialize the service status and register the service control handler with the name of the service.
1049
1050 gServiceStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
1051 gServiceStatus.dwCurrentState = 0;
1052 gServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_POWEREVENT;
1053 gServiceStatus.dwWin32ExitCode = NO_ERROR;
1054 gServiceStatus.dwServiceSpecificExitCode = NO_ERROR;
1055 gServiceStatus.dwCheckPoint = 0;
1056 gServiceStatus.dwWaitHint = 0;
1057
1058 gServiceStatusHandle = RegisterServiceCtrlHandlerEx( argv[ 0 ], ServiceControlHandler, NULL );
1059 err = translate_errno( gServiceStatusHandle, (OSStatus) GetLastError(), kInUseErr );
1060 require_noerr( err, exit );
1061
1062 // Mark the service as starting.
1063
1064 gServiceStatus.dwCurrentState = SERVICE_START_PENDING;
1065 gServiceStatus.dwCheckPoint = 0;
1066 gServiceStatus.dwWaitHint = 5000; // 5 seconds
1067 ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
1068 check_translated_errno( ok, GetLastError(), kParamErr );
1069
1070 // Run the service. This does not return until the service quits or is stopped.
1071
1072 err = ServiceRun( (int) argc, argv );
1073 if( err != kNoErr )
1074 {
1075 gServiceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
1076 gServiceStatus.dwServiceSpecificExitCode = (DWORD) err;
1077 }
1078
1079 // Service-specific work is done so mark the service as stopped.
1080
1081 gServiceStatus.dwCurrentState = SERVICE_STOPPED;
1082 ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
1083 check_translated_errno( ok, GetLastError(), kParamErr );
1084
1085 // Note: The service status handle should not be closed according to Microsoft documentation.
1086
1087 exit:
1088 if( gServiceEventSource )
1089 {
1090 ok = DeregisterEventSource( gServiceEventSource );
1091 check_translated_errno( ok, GetLastError(), kUnknownErr );
1092 gServiceEventSource = NULL;
1093 }
1094 }
1095
1096 //===========================================================================================================================
1097 // ServiceSetupEventLogging
1098 //===========================================================================================================================
1099
1100 static OSStatus ServiceSetupEventLogging( void )
1101 {
1102 OSStatus err;
1103 HKEY key;
1104 LPCTSTR s;
1105 DWORD typesSupported;
1106 TCHAR path[ MAX_PATH ];
1107 DWORD n;
1108
1109 key = NULL;
1110
1111 // Add/Open source name as a sub-key under the Application key in the EventLog registry key.
1112
1113 s = TEXT("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\") kServiceName;
1114 err = RegCreateKey( HKEY_LOCAL_MACHINE, s, &key );
1115 require_noerr( err, exit );
1116
1117 // Add the name to the EventMessageFile subkey.
1118
1119 path[ 0 ] = '\0';
1120 GetModuleFileName( NULL, path, MAX_PATH );
1121 n = (DWORD) ( ( StrLen( path ) + 1 ) * sizeof( TCHAR ) );
1122 err = RegSetValueEx( key, TEXT("EventMessageFile"), 0, REG_EXPAND_SZ, (const LPBYTE) path, n );
1123 require_noerr( err, exit );
1124
1125 // Set the supported event types in the TypesSupported subkey.
1126
1127 typesSupported = 0
1128 | EVENTLOG_SUCCESS
1129 | EVENTLOG_ERROR_TYPE
1130 | EVENTLOG_WARNING_TYPE
1131 | EVENTLOG_INFORMATION_TYPE
1132 | EVENTLOG_AUDIT_SUCCESS
1133 | EVENTLOG_AUDIT_FAILURE;
1134 err = RegSetValueEx( key, TEXT("TypesSupported"), 0, REG_DWORD, (const LPBYTE) &typesSupported, sizeof( DWORD ) );
1135 require_noerr( err, exit );
1136
1137 // Set up the event source.
1138
1139 gServiceEventSource = RegisterEventSource( NULL, kServiceName );
1140 err = translate_errno( gServiceEventSource, (OSStatus) GetLastError(), kParamErr );
1141 require_noerr( err, exit );
1142
1143 exit:
1144 if( key )
1145 {
1146 RegCloseKey( key );
1147 }
1148 return( err );
1149 }
1150
1151 //===========================================================================================================================
1152 // ServiceControlHandler
1153 //===========================================================================================================================
1154
1155 static DWORD WINAPI ServiceControlHandler( DWORD inControl, DWORD inEventType, LPVOID inEventData, LPVOID inContext )
1156 {
1157 BOOL setStatus;
1158 BOOL ok;
1159
1160 DEBUG_UNUSED( inEventData );
1161 DEBUG_UNUSED( inContext );
1162
1163 setStatus = TRUE;
1164 switch( inControl )
1165 {
1166 case SERVICE_CONTROL_STOP:
1167 dlog( kDebugLevelInfo, DEBUG_NAME "ServiceControlHandler: SERVICE_CONTROL_STOP\n" );
1168
1169 ServiceStop();
1170 setStatus = FALSE;
1171 break;
1172
1173 case SERVICE_CONTROL_POWEREVENT:
1174
1175 if (inEventType == PBT_APMSUSPEND)
1176 {
1177 LARGE_INTEGER timeout;
1178
1179 dlog( kDebugLevelInfo, DEBUG_NAME "ServiceControlHandler: PBT_APMSUSPEND\n" );
1180
1181 mDNSPlatformLock( &gMDNSRecord );
1182
1183 gMDNSRecord.SystemWakeOnLANEnabled = SystemWakeForNetworkAccess( &timeout );
1184
1185 if ( gMDNSRecord.SystemWakeOnLANEnabled )
1186 {
1187 ok = SetWaitableTimer( gSPSWakeupEvent, &timeout, 0, NULL, NULL, TRUE );
1188 check( ok );
1189 }
1190
1191 mDNSPlatformUnlock( &gMDNSRecord );
1192
1193 mDNSCoreMachineSleep(&gMDNSRecord, TRUE);
1194 }
1195 else if (inEventType == PBT_APMRESUMESUSPEND)
1196 {
1197 dlog( kDebugLevelInfo, DEBUG_NAME "ServiceControlHandler: PBT_APMRESUMESUSPEND\n" );
1198
1199 mDNSPlatformLock( &gMDNSRecord );
1200
1201 if ( gSPSWakeupEvent )
1202 {
1203 CancelWaitableTimer( gSPSWakeupEvent );
1204 }
1205
1206 if ( gSPSSleepEvent )
1207 {
1208 CancelWaitableTimer( gSPSSleepEvent );
1209 }
1210
1211 mDNSPlatformUnlock( &gMDNSRecord );
1212
1213 mDNSCoreMachineSleep(&gMDNSRecord, FALSE);
1214 }
1215
1216 break;
1217
1218 default:
1219 dlog( kDebugLevelNotice, DEBUG_NAME "ServiceControlHandler: event (0x%08X)\n", inControl );
1220 break;
1221 }
1222
1223 if( setStatus && gServiceStatusHandle )
1224 {
1225 ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
1226 check_translated_errno( ok, GetLastError(), kUnknownErr );
1227 }
1228
1229 return NO_ERROR;
1230 }
1231
1232 //===========================================================================================================================
1233 // ServiceRun
1234 //===========================================================================================================================
1235
1236 static OSStatus ServiceRun( int argc, LPTSTR argv[] )
1237 {
1238 OSStatus err;
1239 BOOL initialized;
1240 BOOL ok;
1241
1242 DEBUG_UNUSED( argc );
1243 DEBUG_UNUSED( argv );
1244
1245 initialized = FALSE;
1246
1247 // <rdar://problem/5727548> Make the service as running before we call ServiceSpecificInitialize. We've
1248 // had reports that some machines with McAfee firewall installed cause a problem with iTunes installation.
1249 // We think that the firewall product is interferring with code in ServiceSpecificInitialize. So as a
1250 // simple workaround, we'll mark us as running *before* we call ServiceSpecificInitialize. This will unblock
1251 // any installers that are waiting for our state to change.
1252
1253 gServiceStatus.dwCurrentState = SERVICE_RUNNING;
1254 ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
1255 check_translated_errno( ok, GetLastError(), kParamErr );
1256
1257 // Initialize the service-specific stuff
1258
1259 err = ServiceSpecificInitialize( argc, argv );
1260 require_noerr( err, exit );
1261 initialized = TRUE;
1262
1263 err = CheckFirewall();
1264 check_noerr( err );
1265
1266 if ( err )
1267 {
1268 gRetryFirewall = TRUE;
1269 }
1270
1271 // Run the service-specific stuff. This does not return until the service quits or is stopped.
1272
1273 ReportStatus( EVENTLOG_INFORMATION_TYPE, "mDNSResponder started\n" );
1274 err = ServiceSpecificRun( argc, argv );
1275 ReportStatus( EVENTLOG_INFORMATION_TYPE, "mDNSResponder stopped (%d)\n", err );
1276 require_noerr( err, exit );
1277
1278 // Service stopped. Clean up and we're done.
1279
1280 exit:
1281 if( initialized )
1282 {
1283 ServiceSpecificFinalize( argc, argv );
1284 }
1285 return( err );
1286 }
1287
1288 //===========================================================================================================================
1289 // ServiceStop
1290 //===========================================================================================================================
1291
1292 static void ServiceStop( void )
1293 {
1294 BOOL ok;
1295 OSStatus err;
1296
1297 // Signal the event to cause the service to exit.
1298
1299 if( gServiceStatusHandle )
1300 {
1301 gServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
1302 ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
1303 check_translated_errno( ok, GetLastError(), kParamErr );
1304 }
1305
1306 err = ServiceSpecificStop();
1307 check_noerr( err );
1308 }
1309
1310 #if 0
1311 #pragma mark -
1312 #pragma mark == Service Specific ==
1313 #endif
1314
1315 //===========================================================================================================================
1316 // ServiceSpecificInitialize
1317 //===========================================================================================================================
1318
1319 static OSStatus ServiceSpecificInitialize( int argc, LPTSTR argv[] )
1320 {
1321 OSVERSIONINFO osInfo;
1322 OSStatus err;
1323 BOOL ok;
1324
1325 DEBUG_UNUSED( argc );
1326 DEBUG_UNUSED( argv );
1327
1328 mDNSPlatformMemZero( &gMDNSRecord, sizeof gMDNSRecord);
1329 mDNSPlatformMemZero( &gPlatformStorage, sizeof gPlatformStorage);
1330
1331 gPlatformStorage.idleThreadCallback = udsIdle;
1332 gPlatformStorage.hostDescriptionChangedCallback = HostDescriptionChanged;
1333
1334 InitializeCriticalSection(&gEventSourceLock);
1335
1336 gStopEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
1337 err = translate_errno( gStopEvent, errno_compat(), kNoResourcesErr );
1338 require_noerr( err, exit );
1339
1340 gSPSWakeupEvent = CreateWaitableTimer( NULL, FALSE, NULL );
1341 err = translate_errno( gSPSWakeupEvent, (mStatus) GetLastError(), kUnknownErr );
1342 require_noerr( err, exit );
1343
1344 gSPSSleepEvent = CreateWaitableTimer( NULL, FALSE, NULL );
1345 err = translate_errno( gSPSSleepEvent, (mStatus) GetLastError(), kUnknownErr );
1346 require_noerr( err, exit );
1347
1348 err = mDNS_Init( &gMDNSRecord, &gPlatformStorage, gRRCache, RR_CACHE_SIZE, mDNS_Init_AdvertiseLocalAddresses, CoreCallback, mDNS_Init_NoInitCallbackContext);
1349 require_noerr( err, exit);
1350
1351 err = udsserver_init(mDNSNULL, 0);
1352 require_noerr( err, exit);
1353
1354 //
1355 // Get the version of Windows that we're running on
1356 //
1357 osInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
1358 ok = GetVersionEx( &osInfo );
1359 err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
1360 require_noerr( err, exit );
1361 gOSMajorVersion = osInfo.dwMajorVersion;
1362 gOSMinorVersion = osInfo.dwMinorVersion;
1363
1364 SetLLRoute( &gMDNSRecord );
1365
1366 exit:
1367 if( err != kNoErr )
1368 {
1369 ServiceSpecificFinalize( argc, argv );
1370 }
1371 return( err );
1372 }
1373
1374 //===========================================================================================================================
1375 // ServiceSpecificRun
1376 //===========================================================================================================================
1377
1378 static OSStatus ServiceSpecificRun( int argc, LPTSTR argv[] )
1379 {
1380 DWORD timeout;
1381 DWORD result;
1382
1383 DEBUG_UNUSED( argc );
1384 DEBUG_UNUSED( argv );
1385
1386 // Main event loop. Process connection requests and state changes (i.e. quit).
1387
1388 timeout = ( gRetryFirewall ) ? kRetryFirewallPeriod : INFINITE;
1389
1390 for ( ;; )
1391 {
1392 HANDLE waitList[ 3 ];
1393
1394 waitList[ 0 ] = gStopEvent;
1395 waitList[ 1 ] = gSPSWakeupEvent;
1396 waitList[ 2 ] = gSPSSleepEvent;
1397
1398 result = WaitForMultipleObjects( 3, waitList, FALSE, timeout );
1399
1400 if ( result == WAIT_OBJECT_0 )
1401 {
1402 break;
1403 }
1404 else if ( result == WAIT_OBJECT_0 + 1 )
1405 {
1406 __int64 temp;
1407 LARGE_INTEGER timeout;
1408
1409 dlog( kDebugLevelInfo, DEBUG_NAME "setting suspend event\n" );
1410
1411 // Stay awake for 60 seconds
1412
1413 temp = -60 * 10000000;
1414 timeout.LowPart = (DWORD) ( temp & 0xFFFFFFFF );
1415 timeout.HighPart = (LONG) ( temp >> 32 );
1416
1417 SetWaitableTimer( gSPSSleepEvent, &timeout, 0, NULL, NULL, TRUE );
1418 }
1419 else if ( result == WAIT_OBJECT_0 + 2 )
1420 {
1421 dlog( kDebugLevelInfo, DEBUG_NAME "suspending machine\n" );
1422 SetSuspendState( FALSE, FALSE, FALSE );
1423 }
1424 else if ( result == WAIT_TIMEOUT )
1425 {
1426 OSStatus err;
1427
1428 err = CheckFirewall();
1429 check_noerr( err );
1430
1431 timeout = INFINITE;
1432 }
1433 else
1434 {
1435 // Unexpected wait result.
1436 dlog( kDebugLevelWarning, DEBUG_NAME "%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__, result );
1437 }
1438 }
1439
1440 return kNoErr;
1441 }
1442
1443 //===========================================================================================================================
1444 // ServiceSpecificStop
1445 //===========================================================================================================================
1446
1447 static OSStatus ServiceSpecificStop( void )
1448 {
1449 OSStatus err;
1450 BOOL ok;
1451
1452 ok = SetEvent(gStopEvent);
1453 err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
1454 require_noerr( err, exit );
1455 exit:
1456 return( err );
1457 }
1458
1459 //===========================================================================================================================
1460 // ServiceSpecificFinalize
1461 //===========================================================================================================================
1462
1463 static void ServiceSpecificFinalize( int argc, LPTSTR argv[] )
1464 {
1465 DEBUG_UNUSED( argc );
1466 DEBUG_UNUSED( argv );
1467
1468 //
1469 // clean up any open sessions
1470 //
1471 while (gEventSources.Head)
1472 {
1473 EventSourceFinalize((Win32EventSource*) gEventSources.Head);
1474 }
1475 //
1476 // give a chance for the udsserver code to clean up
1477 //
1478 udsserver_exit();
1479
1480 //
1481 // and finally close down the mDNSCore
1482 //
1483 mDNS_Close(&gMDNSRecord);
1484
1485 //
1486 // clean up the event sources mutex...no one should be using it now
1487 //
1488 DeleteCriticalSection(&gEventSourceLock);
1489
1490 if ( gSPSWakeupEvent )
1491 {
1492 CloseHandle( gSPSWakeupEvent );
1493 gSPSWakeupEvent = NULL;
1494 }
1495
1496 if ( gSPSSleepEvent )
1497 {
1498 CloseHandle( gSPSSleepEvent );
1499 gSPSSleepEvent = NULL;
1500 }
1501
1502 if ( gStopEvent )
1503 {
1504 CloseHandle( gStopEvent );
1505 gStopEvent = NULL;
1506 }
1507
1508 //
1509 // clean up loaded library
1510 //
1511
1512 if( gIPHelperLibraryInstance )
1513 {
1514 gGetIpInterfaceEntryFunctionPtr = NULL;
1515
1516 FreeLibrary( gIPHelperLibraryInstance );
1517 gIPHelperLibraryInstance = NULL;
1518 }
1519 }
1520
1521
1522 static void
1523 CoreCallback(mDNS * const inMDNS, mStatus status)
1524 {
1525 if (status == mStatus_ConfigChanged)
1526 {
1527 SetLLRoute( inMDNS );
1528 }
1529 }
1530
1531
1532 static mDNSs32
1533 udsIdle(mDNS * const inMDNS, mDNSs32 interval)
1534 {
1535 DEBUG_UNUSED( inMDNS );
1536
1537 //
1538 // rdar://problem/3697326
1539 //
1540 // udsserver_idle wasn't being locked. This resulted
1541 // in multiple threads contesting for the all_requests
1542 // data structure in uds_daemon.c
1543 //
1544 mDNSPlatformLock(&gMDNSRecord);
1545
1546 interval = udsserver_idle(interval);
1547
1548 mDNSPlatformUnlock(&gMDNSRecord);
1549
1550 return interval;
1551 }
1552
1553
1554 static void
1555 HostDescriptionChanged(mDNS * const inMDNS)
1556 {
1557 DEBUG_UNUSED( inMDNS );
1558
1559 udsserver_handle_configchange(inMDNS);
1560 }
1561
1562
1563 mDNSlocal unsigned WINAPI
1564 udsSocketThread(LPVOID inParam)
1565 {
1566 Win32EventSource * source = (Win32EventSource*) inParam;
1567 DWORD threadID = GetCurrentThreadId();
1568 DWORD waitCount;
1569 HANDLE waitList[2];
1570 bool safeToClose;
1571 bool done;
1572 bool locked = false;
1573 mStatus err = 0;
1574
1575 waitCount = source->waitCount;
1576 waitList[0] = source->waitList[0];
1577 waitList[1] = source->waitList[1];
1578 done = (bool) (source->flags & EventSourceFinalized);
1579
1580 while (!done)
1581 {
1582 DWORD result;
1583
1584 result = WaitForMultipleObjects(waitCount, waitList, FALSE, INFINITE);
1585
1586 mDNSPlatformLock(&gMDNSRecord);
1587 locked = true;
1588
1589 // <rdar://problem/3838237>
1590 //
1591 // Look up the source by the thread id. This will ensure that the
1592 // source is still extant. It could already have been deleted
1593 // by the processing thread.
1594 //
1595
1596 EventSourceLock();
1597
1598 for (source = gEventSources.Head; source; source = source->next)
1599 {
1600 if (source->threadID == threadID)
1601 {
1602 break;
1603 }
1604 }
1605
1606 EventSourceUnlock();
1607
1608 if (source == NULL)
1609 {
1610 goto exit;
1611 }
1612
1613 //
1614 // socket event
1615 //
1616 if (result == WAIT_OBJECT_0)
1617 {
1618 source->callback( (int) source->sock, 0, source->context);
1619 }
1620 //
1621 // close event
1622 //
1623 else if (result == WAIT_OBJECT_0 + 1)
1624 {
1625 //
1626 // this is a bit of a hack. we want to clean up the internal data structures
1627 // so we'll go in here and it will clean up for us
1628 //
1629 shutdown(source->sock, 2);
1630 source->callback( (int) source->sock, 0, source->context);
1631
1632 break;
1633 }
1634 else
1635 {
1636 // Unexpected wait result.
1637 dlog( kDebugLevelWarning, DEBUG_NAME "%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__, result );
1638 goto exit;
1639 }
1640
1641 done = (bool) (source->flags & EventSourceFinalized);
1642
1643 mDNSPlatformUnlock(&gMDNSRecord);
1644 locked = false;
1645 }
1646
1647 EventSourceLock();
1648 source->flags |= EventSourceFlagsThreadDone;
1649 safeToClose = !( source->flags & EventSourceFlagsNoClose );
1650 EventSourceUnlock();
1651
1652 if( safeToClose )
1653 {
1654 EventSourceFinalize( source );
1655 }
1656
1657 exit:
1658
1659 if ( locked )
1660 {
1661 mDNSPlatformUnlock(&gMDNSRecord);
1662 }
1663
1664 _endthreadex_compat( (unsigned) err );
1665 return( (unsigned) err );
1666 }
1667
1668
1669 mStatus
1670 udsSupportAddFDToEventLoop( SocketRef fd, udsEventCallback callback, void *context)
1671 {
1672 Win32EventSource * newSource;
1673 DWORD result;
1674 mStatus err;
1675
1676 newSource = malloc(sizeof(Win32EventSource));
1677 require_action( newSource, exit, err = mStatus_NoMemoryErr );
1678 mDNSPlatformMemZero(newSource, sizeof(Win32EventSource));
1679
1680 newSource->flags = 0;
1681 newSource->sock = (SOCKET) fd;
1682 newSource->callback = callback;
1683 newSource->context = context;
1684
1685 newSource->socketEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
1686 err = translate_errno( newSource->socketEvent, (mStatus) GetLastError(), kUnknownErr );
1687 require_noerr( err, exit );
1688
1689 newSource->closeEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
1690 err = translate_errno( newSource->closeEvent, (mStatus) GetLastError(), kUnknownErr );
1691 require_noerr( err, exit );
1692
1693 err = WSAEventSelect(newSource->sock, newSource->socketEvent, FD_ACCEPT|FD_READ|FD_CLOSE);
1694 err = translate_errno( err == 0, errno_compat(), kNoResourcesErr );
1695 require_noerr( err, exit );
1696
1697 newSource->waitCount = 0;
1698 newSource->waitList[ newSource->waitCount++ ] = newSource->socketEvent;
1699 newSource->waitList[ newSource->waitCount++ ] = newSource->closeEvent;
1700
1701 //
1702 // lock the list
1703 //
1704 EventSourceLock();
1705
1706 // add the event source to the end of the list, while checking
1707 // to see if the list needs to be initialized
1708 //
1709 if ( gEventSources.LinkOffset == 0)
1710 {
1711 InitLinkedList( &gEventSources, offsetof( Win32EventSource, next));
1712 }
1713
1714 AddToTail( &gEventSources, newSource);
1715
1716 //
1717 // no longer using the list
1718 //
1719 EventSourceUnlock();
1720
1721 // Create thread with _beginthreadex() instead of CreateThread() to avoid memory leaks when using static run-time
1722 // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
1723 // Create the thread suspended then resume it so the thread handle and ID are valid before the thread starts running.
1724 newSource->threadHandle = (HANDLE) _beginthreadex_compat( NULL, 0, udsSocketThread, newSource, CREATE_SUSPENDED, &newSource->threadID );
1725 err = translate_errno( newSource->threadHandle, (mStatus) GetLastError(), kUnknownErr );
1726 require_noerr( err, exit );
1727
1728 result = ResumeThread( newSource->threadHandle );
1729 err = translate_errno( result != (DWORD) -1, errno_compat(), kNoResourcesErr );
1730 require_noerr( err, exit );
1731
1732 exit:
1733
1734 if (err && newSource)
1735 {
1736 EventSourceFinalize(newSource);
1737 }
1738
1739 return err;
1740 }
1741
1742
1743 mStatus
1744 udsSupportRemoveFDFromEventLoop( SocketRef fd) // Note: This also CLOSES the socket
1745 {
1746 Win32EventSource * source;
1747 mStatus err = mStatus_NoError;
1748
1749 //
1750 // find the event source
1751 //
1752 EventSourceLock();
1753
1754 for (source = gEventSources.Head; source; source = source->next)
1755 {
1756 if (source->sock == (SOCKET) fd)
1757 {
1758 break;
1759 }
1760 }
1761
1762 //
1763 // if we found him, finalize him
1764 //
1765 if (source != NULL)
1766 {
1767 EventSourceFinalize(source);
1768 }
1769
1770 //
1771 // done with the list
1772 //
1773 EventSourceUnlock();
1774
1775 closesocket(fd);
1776
1777 return err;
1778 }
1779
1780
1781 mDNSexport void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay)
1782 {
1783 (void)m;
1784 (void)delay;
1785 // No-op, for now
1786 }
1787
1788
1789 static mStatus
1790 EventSourceFinalize(Win32EventSource * source)
1791 {
1792 OSStatus err;
1793 bool locked;
1794 Win32EventSource * inserted;
1795 bool sameThread;
1796 bool deferClose;
1797 BOOL ok;
1798 DWORD threadID;
1799 DWORD result;
1800
1801 check( source );
1802
1803 // Find the session in the list.
1804
1805 EventSourceLock();
1806 locked = true;
1807
1808 for( inserted = (Win32EventSource*) gEventSources.Head; inserted; inserted = inserted->next )
1809 {
1810 if( inserted == source )
1811 {
1812 break;
1813 }
1814 }
1815 require_action( inserted, exit, err = kNotFoundErr );
1816
1817 //
1818 // note that we've had finalize called
1819 //
1820 source->flags |= EventSourceFinalized;
1821
1822 // If we're being called from the same thread as the session (e.g. message callback is closing the session) then
1823 // we must defer the close until the thread is done because the thread is still using the session object.
1824
1825 deferClose = false;
1826 threadID = GetCurrentThreadId();
1827 sameThread = source->threadHandle && ( threadID == source->threadID );
1828 if( sameThread && !( source->flags & EventSourceFlagsThreadDone ) )
1829 {
1830 source->flags &= ~EventSourceFlagsNoClose;
1831 deferClose = true;
1832 }
1833
1834 // If the thread we're not being called from the session thread, but the thread has already marked itself as
1835 // as done (e.g. session closed from something like a peer disconnect and at the same time the client also
1836 // tried to close) then we only want to continue with the close if the thread is not going to close itself.
1837
1838 if( !sameThread && ( source->flags & EventSourceFlagsThreadDone ) && !( source->flags & EventSourceFlagsNoClose ) )
1839 {
1840 deferClose = true;
1841 }
1842
1843 // Signal a close so the thread exits.
1844
1845 if( source->closeEvent )
1846 {
1847 ok = SetEvent( source->closeEvent );
1848 check_translated_errno( ok, errno_compat(), kUnknownErr );
1849 }
1850 if( deferClose )
1851 {
1852 err = kNoErr;
1853 goto exit;
1854 }
1855
1856 source->flags |= EventSourceFlagsNoClose;
1857
1858 // Remove the session from the list.
1859 RemoveFromList(&gEventSources, source);
1860
1861 EventSourceUnlock();
1862 locked = false;
1863
1864 // Wait for the thread to exit. Give up after 3 seconds to handle a hung thread.
1865
1866 if( source->threadHandle && ( threadID != source->threadID ) )
1867 {
1868 result = WaitForSingleObject( source->threadHandle, 3 * 1000 );
1869 check_translated_errno( result == WAIT_OBJECT_0, (OSStatus) GetLastError(), result );
1870 }
1871
1872 // Release the thread.
1873
1874 if( source->threadHandle )
1875 {
1876 ok = CloseHandle( source->threadHandle );
1877 check_translated_errno( ok, errno_compat(), kUnknownErr );
1878 source->threadHandle = NULL;
1879 }
1880
1881 // Release the socket event.
1882
1883 if( source->socketEvent )
1884 {
1885 ok = CloseHandle( source->socketEvent );
1886 check_translated_errno( ok, errno_compat(), kUnknownErr );
1887 source->socketEvent = NULL;
1888 }
1889
1890 // Release the close event.
1891
1892 if( source->closeEvent )
1893 {
1894 ok = CloseHandle( source->closeEvent );
1895 check_translated_errno( ok, errno_compat(), kUnknownErr );
1896 source->closeEvent = NULL;
1897 }
1898
1899 // Release the memory used by the object.
1900 free ( source );
1901
1902 err = kNoErr;
1903
1904 dlog( kDebugLevelNotice, DEBUG_NAME "session closed\n" );
1905
1906 exit:
1907
1908 if( locked )
1909 {
1910 EventSourceUnlock();
1911 }
1912
1913 return( err );
1914 }
1915
1916
1917 static void
1918 EventSourceLock()
1919 {
1920 EnterCriticalSection(&gEventSourceLock);
1921 }
1922
1923
1924 static void
1925 EventSourceUnlock()
1926 {
1927 LeaveCriticalSection(&gEventSourceLock);
1928 }
1929
1930
1931 //===========================================================================================================================
1932 // SystemWakeForNetworkAccess
1933 //===========================================================================================================================
1934
1935 mDNSu8
1936 SystemWakeForNetworkAccess( LARGE_INTEGER * timeout )
1937 {
1938 HKEY key = NULL;
1939 DWORD dwSize;
1940 DWORD enabled;
1941 mDNSu8 ok;
1942 SYSTEM_POWER_STATUS powerStatus;
1943 time_t startTime;
1944 time_t nextWakeupTime;
1945 time_t delta;
1946 __int64 delta64;
1947 DWORD err;
1948
1949 dlog( kDebugLevelInfo, DEBUG_NAME "SystemWakeForNetworkAccess\n" );
1950
1951 // Make sure we have a timer
1952
1953 require_action( gSPSWakeupEvent != NULL, exit, ok = FALSE );
1954 require_action( gSPSSleepEvent != NULL, exit, ok = FALSE );
1955
1956 // Make sure the user enabled bonjour sleep proxy client
1957
1958 err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Power Management", &key );
1959 require_action( !err, exit, ok = FALSE );
1960 dwSize = sizeof( DWORD );
1961 err = RegQueryValueEx( key, L"Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize );
1962 require_action( !err, exit, ok = FALSE );
1963 require_action( enabled, exit, ok = FALSE );
1964
1965 // Make sure machine is on AC power
1966
1967 ok = ( mDNSu8 ) GetSystemPowerStatus( &powerStatus );
1968 require_action( ok, exit, ok = FALSE );
1969 require_action( powerStatus.ACLineStatus == AC_LINE_ONLINE, exit, ok = FALSE );
1970
1971 // Now make sure we have a network interface that does wake-on-lan
1972
1973 UpdateWOMPConfig( &gMDNSRecord );
1974 require_action( gMDNSRecord.p->womp, exit, ok = FALSE );
1975
1976 // Calculate next wake up time
1977
1978 startTime = time( NULL );
1979 nextWakeupTime = startTime + ( 120 * 60 );
1980
1981 if ( gMDNSRecord.p->nextDHCPLeaseExpires < nextWakeupTime )
1982 {
1983 nextWakeupTime = gMDNSRecord.p->nextDHCPLeaseExpires;
1984 }
1985
1986 // Finally calculate the next relative wakeup time
1987
1988 delta = ( time_t ) ( ( ( double )( nextWakeupTime - startTime ) ) * 0.9 );
1989 delta64 = -delta * 10000000;
1990 timeout->LowPart = (DWORD) ( delta64 & 0xFFFFFFFF );
1991 timeout->HighPart = (LONG) ( delta64 >> 32 );
1992
1993 dlog( kDebugLevelInfo, DEBUG_NAME "enabling sleep proxy client with next wakeup time %d seconds from now\n", delta );
1994
1995 ok = TRUE;
1996
1997 exit:
1998
1999 if ( key )
2000 {
2001 RegCloseKey( key );
2002 }
2003
2004 return ok;
2005 }
2006
2007
2008 //===========================================================================================================================
2009 // HaveRoute
2010 //===========================================================================================================================
2011
2012 static bool
2013 HaveRoute( PMIB_IPFORWARDROW rowExtant, unsigned long addr, unsigned long metric )
2014 {
2015 PMIB_IPFORWARDTABLE pIpForwardTable = NULL;
2016 DWORD dwSize = 0;
2017 BOOL bOrder = FALSE;
2018 OSStatus err;
2019 bool found = false;
2020 unsigned long int i;
2021
2022 //
2023 // Find out how big our buffer needs to be.
2024 //
2025 err = GetIpForwardTable(NULL, &dwSize, bOrder);
2026 require_action( err == ERROR_INSUFFICIENT_BUFFER, exit, err = kUnknownErr );
2027
2028 //
2029 // Allocate the memory for the table
2030 //
2031 pIpForwardTable = (PMIB_IPFORWARDTABLE) malloc( dwSize );
2032 require_action( pIpForwardTable, exit, err = kNoMemoryErr );
2033
2034 //
2035 // Now get the table.
2036 //
2037 err = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder);
2038 require_noerr( err, exit );
2039
2040 //
2041 // Search for the row in the table we want.
2042 //
2043 for ( i = 0; i < pIpForwardTable->dwNumEntries; i++)
2044 {
2045 if ( ( pIpForwardTable->table[i].dwForwardDest == addr ) && ( !metric || ( pIpForwardTable->table[i].dwForwardMetric1 == metric ) ) )
2046 {
2047 memcpy( rowExtant, &(pIpForwardTable->table[i]), sizeof(*rowExtant) );
2048 found = true;
2049 break;
2050 }
2051 }
2052
2053 exit:
2054
2055 if ( pIpForwardTable != NULL )
2056 {
2057 free(pIpForwardTable);
2058 }
2059
2060 return found;
2061 }
2062
2063
2064 //===========================================================================================================================
2065 // IsValidAddress
2066 //===========================================================================================================================
2067
2068 static bool
2069 IsValidAddress( const char * addr )
2070 {
2071 return ( addr && ( strcmp( addr, "0.0.0.0" ) != 0 ) ) ? true : false;
2072 }
2073
2074
2075 //===========================================================================================================================
2076 // GetAdditionalMetric
2077 //===========================================================================================================================
2078
2079 static ULONG
2080 GetAdditionalMetric( DWORD ifIndex )
2081 {
2082 ULONG metric = 0;
2083
2084 if( !gIPHelperLibraryInstance )
2085 {
2086 gIPHelperLibraryInstance = LoadLibrary( TEXT( "Iphlpapi" ) );
2087
2088 gGetIpInterfaceEntryFunctionPtr =
2089 (GetIpInterfaceEntryFunctionPtr) GetProcAddress( gIPHelperLibraryInstance, "GetIpInterfaceEntry" );
2090
2091 if( !gGetIpInterfaceEntryFunctionPtr )
2092 {
2093 BOOL ok;
2094
2095 ok = FreeLibrary( gIPHelperLibraryInstance );
2096 check_translated_errno( ok, GetLastError(), kUnknownErr );
2097 gIPHelperLibraryInstance = NULL;
2098 }
2099 }
2100
2101 if ( gGetIpInterfaceEntryFunctionPtr )
2102 {
2103 MIB_IPINTERFACE_ROW row;
2104 DWORD err;
2105
2106 ZeroMemory( &row, sizeof( MIB_IPINTERFACE_ROW ) );
2107 row.Family = AF_INET;
2108 row.InterfaceIndex = ifIndex;
2109 err = gGetIpInterfaceEntryFunctionPtr( &row );
2110 require_noerr( err, exit );
2111 metric = row.Metric + 256;
2112 }
2113
2114 exit:
2115
2116 return metric;
2117 }
2118
2119
2120 //===========================================================================================================================
2121 // SetLLRoute
2122 //===========================================================================================================================
2123
2124 static OSStatus
2125 SetLLRoute( mDNS * const inMDNS )
2126 {
2127 OSStatus err = kNoErr;
2128
2129 DEBUG_UNUSED( inMDNS );
2130
2131 //
2132 // <rdar://problem/4096464> Don't call SetLLRoute on loopback
2133 // <rdar://problem/6885843> Default route on Windows 7 breaks network connectivity
2134 //
2135 // Don't mess w/ the routing table on Vista and later OSes, as
2136 // they have a permanent route to link-local addresses. Otherwise,
2137 // set a route to link local addresses (169.254.0.0)
2138 //
2139 if ( ( gOSMajorVersion < 6 ) && gServiceManageLLRouting && !gPlatformStorage.registeredLoopback4 )
2140 {
2141 DWORD ifIndex;
2142 MIB_IPFORWARDROW rowExtant;
2143 bool addRoute;
2144 MIB_IPFORWARDROW row;
2145
2146 ZeroMemory(&row, sizeof(row));
2147
2148 err = GetRouteDestination(&ifIndex, &row.dwForwardNextHop);
2149 require_noerr( err, exit );
2150 row.dwForwardDest = inet_addr(kLLNetworkAddr);
2151 row.dwForwardIfIndex = ifIndex;
2152 row.dwForwardMask = inet_addr(kLLNetworkAddrMask);
2153 row.dwForwardType = 3;
2154 row.dwForwardProto = MIB_IPPROTO_NETMGMT;
2155 row.dwForwardAge = 0;
2156 row.dwForwardPolicy = 0;
2157 row.dwForwardMetric1 = 20 + GetAdditionalMetric( ifIndex );
2158 row.dwForwardMetric2 = (DWORD) - 1;
2159 row.dwForwardMetric3 = (DWORD) - 1;
2160 row.dwForwardMetric4 = (DWORD) - 1;
2161 row.dwForwardMetric5 = (DWORD) - 1;
2162
2163 addRoute = true;
2164
2165 //
2166 // check to make sure we don't already have a route
2167 //
2168 if ( HaveRoute( &rowExtant, inet_addr( kLLNetworkAddr ), 0 ) )
2169 {
2170 //
2171 // set the age to 0 so that we can do a memcmp.
2172 //
2173 rowExtant.dwForwardAge = 0;
2174
2175 //
2176 // check to see if this route is the same as our route
2177 //
2178 if (memcmp(&row, &rowExtant, sizeof(row)) != 0)
2179 {
2180 //
2181 // if it isn't then delete this entry
2182 //
2183 DeleteIpForwardEntry(&rowExtant);
2184 }
2185 else
2186 {
2187 //
2188 // else it is, so we don't want to create another route
2189 //
2190 addRoute = false;
2191 }
2192 }
2193
2194 if (addRoute && row.dwForwardNextHop)
2195 {
2196 err = CreateIpForwardEntry(&row);
2197 check_noerr( err );
2198 }
2199 }
2200
2201 exit:
2202
2203 return ( err );
2204 }
2205
2206
2207 //===========================================================================================================================
2208 // GetRouteDestination
2209 //===========================================================================================================================
2210
2211 static OSStatus
2212 GetRouteDestination(DWORD * ifIndex, DWORD * address)
2213 {
2214 struct in_addr ia;
2215 IP_ADAPTER_INFO * pAdapterInfo = NULL;
2216 IP_ADAPTER_INFO * pAdapter = NULL;
2217 ULONG bufLen;
2218 mDNSBool done = mDNSfalse;
2219 OSStatus err;
2220
2221 //
2222 // GetBestInterface will fail if there is no default gateway
2223 // configured. If that happens, we will just take the first
2224 // interface in the list. MSDN support says there is no surefire
2225 // way to manually determine what the best interface might
2226 // be for a particular network address.
2227 //
2228 ia.s_addr = inet_addr(kLLNetworkAddr);
2229 err = GetBestInterface(*(IPAddr*) &ia, ifIndex);
2230
2231 if (err)
2232 {
2233 *ifIndex = 0;
2234 }
2235
2236 //
2237 // Make an initial call to GetAdaptersInfo to get
2238 // the necessary size into the bufLen variable
2239 //
2240 err = GetAdaptersInfo( NULL, &bufLen);
2241 require_action( err == ERROR_BUFFER_OVERFLOW, exit, err = kUnknownErr );
2242
2243 pAdapterInfo = (IP_ADAPTER_INFO*) malloc( bufLen );
2244 require_action( pAdapterInfo, exit, err = kNoMemoryErr );
2245
2246 err = GetAdaptersInfo( pAdapterInfo, &bufLen);
2247 require_noerr( err, exit );
2248
2249 pAdapter = pAdapterInfo;
2250 err = kUnknownErr;
2251
2252 // <rdar://problem/3718122>
2253 // <rdar://problem/5652098>
2254 //
2255 // Look for the Nortel VPN virtual interface, along with Juniper virtual interface.
2256 //
2257 // If these interfaces are active (i.e., has a non-zero IP Address),
2258 // then we want to disable routing table modifications.
2259
2260 while (pAdapter)
2261 {
2262 if ( ( IsNortelVPN( pAdapter ) || IsJuniperVPN( pAdapter ) || IsCiscoVPN( pAdapter ) ) &&
2263 ( inet_addr( pAdapter->IpAddressList.IpAddress.String ) != 0 ) )
2264 {
2265 dlog( kDebugLevelTrace, DEBUG_NAME "disabling routing table management due to VPN incompatibility" );
2266 goto exit;
2267 }
2268
2269 pAdapter = pAdapter->Next;
2270 }
2271
2272 while ( !done )
2273 {
2274 pAdapter = pAdapterInfo;
2275 err = kUnknownErr;
2276
2277 while (pAdapter)
2278 {
2279 // If we don't have an interface selected, choose the first one that is of type ethernet and
2280 // has a valid IP Address
2281
2282 if ((pAdapter->Type == MIB_IF_TYPE_ETHERNET) && ( IsValidAddress( pAdapter->IpAddressList.IpAddress.String ) ) && (!(*ifIndex) || (pAdapter->Index == (*ifIndex))))
2283 {
2284 *address = inet_addr( pAdapter->IpAddressList.IpAddress.String );
2285 *ifIndex = pAdapter->Index;
2286 err = kNoErr;
2287 break;
2288 }
2289
2290 pAdapter = pAdapter->Next;
2291 }
2292
2293 // If we found the right interface, or we weren't trying to find a specific interface then we're done
2294
2295 if ( !err || !( *ifIndex) )
2296 {
2297 done = mDNStrue;
2298 }
2299
2300 // Otherwise, try again by wildcarding the interface
2301
2302 else
2303 {
2304 *ifIndex = 0;
2305 }
2306 }
2307
2308 exit:
2309
2310 if ( pAdapterInfo != NULL )
2311 {
2312 free( pAdapterInfo );
2313 }
2314
2315 return( err );
2316 }
2317
2318
2319 static bool
2320 IsNortelVPN( IP_ADAPTER_INFO * pAdapter )
2321 {
2322 return ((pAdapter->Type == MIB_IF_TYPE_ETHERNET) &&
2323 (pAdapter->AddressLength == 6) &&
2324 (pAdapter->Address[0] == 0x44) &&
2325 (pAdapter->Address[1] == 0x45) &&
2326 (pAdapter->Address[2] == 0x53) &&
2327 (pAdapter->Address[3] == 0x54) &&
2328 (pAdapter->Address[4] == 0x42) &&
2329 (pAdapter->Address[5] == 0x00)) ? true : false;
2330 }
2331
2332
2333 static bool
2334 IsJuniperVPN( IP_ADAPTER_INFO * pAdapter )
2335 {
2336 return ( strnistr( pAdapter->Description, "Juniper", sizeof( pAdapter->Description ) ) != NULL ) ? true : false;
2337 }
2338
2339
2340 static bool
2341 IsCiscoVPN( IP_ADAPTER_INFO * pAdapter )
2342 {
2343 return ((pAdapter->Type == MIB_IF_TYPE_ETHERNET) &&
2344 (pAdapter->AddressLength == 6) &&
2345 (pAdapter->Address[0] == 0x00) &&
2346 (pAdapter->Address[1] == 0x05) &&
2347 (pAdapter->Address[2] == 0x9a) &&
2348 (pAdapter->Address[3] == 0x3c) &&
2349 (pAdapter->Address[4] == 0x7a) &&
2350 (pAdapter->Address[5] == 0x00)) ? true : false;
2351 }
2352
2353
2354 static const char *
2355 strnistr( const char * string, const char * subString, size_t max )
2356 {
2357 size_t subStringLen;
2358 size_t offset;
2359 size_t maxOffset;
2360 size_t stringLen;
2361 const char * pPos;
2362
2363 if ( ( string == NULL ) || ( subString == NULL ) )
2364 {
2365 return string;
2366 }
2367
2368 stringLen = ( max > strlen( string ) ) ? strlen( string ) : max;
2369
2370 if ( stringLen == 0 )
2371 {
2372 return NULL;
2373 }
2374
2375 subStringLen = strlen( subString );
2376
2377 if ( subStringLen == 0 )
2378 {
2379 return string;
2380 }
2381
2382 if ( subStringLen > stringLen )
2383 {
2384 return NULL;
2385 }
2386
2387 maxOffset = stringLen - subStringLen;
2388 pPos = string;
2389
2390 for ( offset = 0; offset <= maxOffset; offset++ )
2391 {
2392 if ( _strnicmp( pPos, subString, subStringLen ) == 0 )
2393 {
2394 return pPos;
2395 }
2396
2397 pPos++;
2398 }
2399
2400 return NULL;
2401 }
2402