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