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