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