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