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