Fix problem with sleep proxy wakeup event
[people/sha0/mDNSResponder.git] / mDNSWindows / SystemService / Service.c
1 /* -*- Mode: C; tab-width: 4 -*-
2  *
3  * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  * 
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  * 
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #include        <stdio.h>
19 #include        <stdlib.h>
20 #include        <crtdbg.h>
21 #include        <stdarg.h>
22 #include        <stddef.h>
23
24
25 #include        "CommonServices.h"
26 #include        "DebugServices.h"
27 #include        "RegNames.h"
28
29 #include        "uds_daemon.h"
30 #include        "GenLinkedList.h"
31 #include        "Service.h"
32
33 #include        "Resource.h"
34
35 #include        "mDNSEmbeddedAPI.h"
36 #include        "uDNS.h"
37 #include        "mDNSWin32.h"
38
39 #include        "Firewall.h"
40
41 #if( !TARGET_OS_WINDOWS_CE )
42         #include        <mswsock.h>
43         #include        <process.h>
44         #include        <ipExport.h>
45         #include        <ws2def.h>
46         #include        <ws2ipdef.h>
47         #include        <iphlpapi.h>
48         #include        <netioapi.h>
49         #include        <iptypes.h>
50         #include        <powrprof.h>
51 #endif
52
53 #ifndef HeapEnableTerminationOnCorruption
54 #       define HeapEnableTerminationOnCorruption (HEAP_INFORMATION_CLASS)1
55 #endif
56
57 #if 0
58 #pragma mark == Constants ==
59 #endif
60
61 //===========================================================================================================================
62 //      Constants
63 //===========================================================================================================================
64
65 #define DEBUG_NAME                                                      "[mDNSWin32] "
66 #define kServiceFirewallName                            L"Bonjour"
67 #define kServiceDependencies                            TEXT("Tcpip\0\0")
68 #define kDNSServiceCacheEntryCountDefault       512
69 #define kRetryFirewallPeriod                            30 * 1000
70 #define kDefValueSize                                           MAX_PATH + 1
71 #define kZeroIndex                                                      0
72 #define kDefaultRouteMetric                                     399
73
74 #define RR_CACHE_SIZE 500
75 static CacheEntity gRRCache[RR_CACHE_SIZE];
76 #if 0
77 #pragma mark == Structures ==
78 #endif
79
80 //===========================================================================================================================
81 //      Structures
82 //===========================================================================================================================
83
84 typedef struct EventSource
85 {
86         HANDLE                                                  event;
87         void                                            *       context;
88         RegisterWaitableEventHandler    handler;
89         struct EventSource                      *       next;
90 } EventSource;
91
92 static BOOL                                                                                     gEventSourceListChanged = FALSE;
93 static EventSource                                                              *       gEventSourceList = NULL;
94 static int                                                                                      gEventSources = 0;
95
96 #define kWaitListStopEvent                                                      ( WAIT_OBJECT_0 + 0 )
97 #define kWaitListInterfaceListChangedEvent                      ( WAIT_OBJECT_0 + 1 )
98 #define kWaitListComputerDescriptionEvent                       ( WAIT_OBJECT_0 + 2 )
99 #define kWaitListTCPIPEvent                                                     ( WAIT_OBJECT_0 + 3 )
100 #define kWaitListDynDNSEvent                                            ( WAIT_OBJECT_0 + 4 )
101 #define kWaitListFileShareEvent                                         ( WAIT_OBJECT_0 + 5 )
102 #define kWaitListFirewallEvent                                          ( WAIT_OBJECT_0 + 6 )
103 #define kWaitListSPSWakeupEvent                                         ( WAIT_OBJECT_0 + 7 )
104 #define kWaitListSPSSleepEvent                                          ( WAIT_OBJECT_0 + 8 )
105 #define kWaitListFixedItemCount                                         9
106
107
108 #if 0
109 #pragma mark == Prototypes ==
110 #endif
111
112 //===========================================================================================================================
113 //      Prototypes
114 //===========================================================================================================================
115 static void                     Usage( void );
116 static BOOL WINAPI      ConsoleControlHandler( DWORD inControlEvent );
117 static OSStatus         InstallService( LPCTSTR inName, LPCTSTR inDisplayName, LPCTSTR inDescription, LPCTSTR inPath );
118 static OSStatus         RemoveService( LPCTSTR inName );
119 static OSStatus         SetServiceParameters();
120 static OSStatus         GetServiceParameters();
121 static OSStatus         CheckFirewall();
122 static OSStatus         SetServiceInfo( SC_HANDLE inSCM, LPCTSTR inServiceName, LPCTSTR inDescription );
123 static void                     ReportStatus( int inType, const char *inFormat, ... );
124
125 static void WINAPI      ServiceMain( DWORD argc, LPTSTR argv[] );
126 static OSStatus         ServiceSetupEventLogging( void );
127 static DWORD WINAPI     ServiceControlHandler( DWORD inControl, DWORD inEventType, LPVOID inEventData, LPVOID inContext );
128
129 static OSStatus         ServiceRun( int argc, LPTSTR argv[] );
130 static void                     ServiceStop( void );
131
132 static OSStatus         ServiceSpecificInitialize( int argc, LPTSTR  argv[] );
133 static OSStatus         ServiceSpecificRun( int argc, LPTSTR argv[] );
134 static OSStatus         ServiceSpecificStop( void );
135 static void                     ServiceSpecificFinalize( int argc, LPTSTR argv[] );
136 static mStatus          SetupNotifications();
137 static mStatus          TearDownNotifications();
138 static mStatus          RegisterWaitableEvent( mDNS * const inMDNS, HANDLE event, void * context, RegisterWaitableEventHandler handler );
139 static void                     UnregisterWaitableEvent( mDNS * const inMDNS, HANDLE event );
140 static mStatus          SetupWaitList( mDNS * const inMDNS, HANDLE **outWaitList, int *outWaitListCount );
141 static void                     UDSCanAccept( mDNS * const inMDNS, HANDLE event, void * context );
142 static void                     UDSCanRead( TCPSocket * sock );
143 static void                     HandlePowerSuspend( void * v );
144 static void                     HandlePowerResumeSuspend( void * v );
145 static void                     CoreCallback(mDNS * const inMDNS, mStatus result);
146 static mDNSu8           SystemWakeForNetworkAccess( LARGE_INTEGER * timeout );
147 static OSStatus         GetRouteDestination(DWORD * ifIndex, DWORD * address);
148 static OSStatus         SetLLRoute( mDNS * const inMDNS );
149 static bool                     HaveRoute( PMIB_IPFORWARDROW rowExtant, unsigned long addr, unsigned long metric );
150 static bool                     IsValidAddress( const char * addr );
151 static bool                     IsNortelVPN( IP_ADAPTER_INFO * pAdapter );
152 static bool                     IsJuniperVPN( IP_ADAPTER_INFO * pAdapter );
153 static bool                     IsCiscoVPN( IP_ADAPTER_INFO * pAdapter );
154 static const char * strnistr( const char * string, const char * subString, size_t max );
155
156 #if defined(UNICODE)
157 #       define StrLen(X)        wcslen(X)
158 #       define StrCmp(X,Y)      wcscmp(X,Y)
159 #else
160 #       define StrLen(X)        strlen(X)
161 #       define StrCmp(X,Y)      strcmp(X,Y)
162 #endif
163
164
165 #define kLLNetworkAddr      "169.254.0.0"
166 #define kLLNetworkAddrMask  "255.255.0.0"
167
168
169 #include        "mDNSEmbeddedAPI.h"
170
171 #if 0
172 #pragma mark == Globals ==
173 #endif
174
175 //===========================================================================================================================
176 //      Globals
177 //===========================================================================================================================
178 #define gMDNSRecord mDNSStorage
179 DEBUG_LOCAL     mDNS_PlatformSupport            gPlatformStorage;
180 DEBUG_LOCAL BOOL                                                gServiceQuietMode               = FALSE;
181 DEBUG_LOCAL SERVICE_TABLE_ENTRY                 gServiceDispatchTable[] = 
182 {
183         { kServiceName, ServiceMain }, 
184         { NULL,                 NULL }
185 };
186 DEBUG_LOCAL SOCKET                                              gInterfaceListChangedSocket     = INVALID_SOCKET;
187 DEBUG_LOCAL HANDLE                                              gInterfaceListChangedEvent      = NULL;
188 DEBUG_LOCAL HKEY                                                gDescKey                                        = NULL;
189 DEBUG_LOCAL HANDLE                                              gDescChangedEvent                       = NULL; // Computer description changed event
190 DEBUG_LOCAL HKEY                                                gTcpipKey                                       = NULL;
191 DEBUG_LOCAL HANDLE                                              gTcpipChangedEvent                      = NULL; // TCP/IP config changed
192 DEBUG_LOCAL HKEY                                                gDdnsKey                                        = NULL;
193 DEBUG_LOCAL HANDLE                                              gDdnsChangedEvent                       = NULL; // DynDNS config changed
194 DEBUG_LOCAL HKEY                                                gFileSharingKey                         = NULL;
195 DEBUG_LOCAL HANDLE                                              gFileSharingChangedEvent        = NULL; // File Sharing changed
196 DEBUG_LOCAL HKEY                                                gFirewallKey                            = NULL;
197 DEBUG_LOCAL HANDLE                                              gFirewallChangedEvent           = NULL; // Firewall changed
198 DEBUG_LOCAL SERVICE_STATUS                              gServiceStatus;
199 DEBUG_LOCAL SERVICE_STATUS_HANDLE               gServiceStatusHandle    = NULL;
200 DEBUG_LOCAL HANDLE                                              gServiceEventSource             = NULL;
201 DEBUG_LOCAL bool                                                gServiceAllowRemote             = false;
202 DEBUG_LOCAL int                                                 gServiceCacheEntryCount = 0;    // 0 means to use the DNS-SD default.
203 DEBUG_LOCAL bool                                                gServiceManageLLRouting = true;
204 DEBUG_LOCAL int                                                 gWaitCount                              = 0;
205 DEBUG_LOCAL HANDLE                                      *       gWaitList                               = NULL;
206 DEBUG_LOCAL HANDLE                                              gStopEvent                              = NULL;
207 DEBUG_LOCAL HANDLE                                              gSPSWakeupEvent                 = NULL;
208 DEBUG_LOCAL HANDLE                                              gSPSSleepEvent                  = NULL;
209 DEBUG_LOCAL HANDLE                                              gUDSEvent                               = NULL;
210 DEBUG_LOCAL SocketRef                                   gUDSSocket                              = 0;
211 DEBUG_LOCAL udsEventCallback                    gUDSCallback                    = NULL;
212 DEBUG_LOCAL BOOL                                                gRetryFirewall                  = FALSE;
213 DEBUG_LOCAL DWORD                                               gOSMajorVersion;
214 DEBUG_LOCAL DWORD                                               gOSMinorVersion;
215
216 typedef DWORD ( WINAPI * GetIpInterfaceEntryFunctionPtr )( PMIB_IPINTERFACE_ROW );
217 mDNSlocal HMODULE                                                               gIPHelperLibraryInstance                = NULL;
218 mDNSlocal GetIpInterfaceEntryFunctionPtr                gGetIpInterfaceEntryFunctionPtr = NULL;
219
220
221 #if 0
222 #pragma mark -
223 #endif
224
225 //===========================================================================================================================
226 //      Main
227 //===========================================================================================================================
228 int     Main( int argc, LPTSTR argv[] )
229 {
230         OSStatus                err;
231         BOOL                    ok;
232         BOOL                    start;
233         int                             i;
234
235         HeapSetInformation( NULL, HeapEnableTerminationOnCorruption, NULL, 0 );
236
237         debug_initialize( kDebugOutputTypeMetaConsole );
238         debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelVerbose );
239
240         // Default to automatically starting the service dispatcher if no extra arguments are specified.
241         
242         start = ( argc <= 1 );
243         
244         // Parse arguments.
245         
246         for( i = 1; i < argc; ++i )
247         {
248                 if( StrCmp( argv[ i ], TEXT("-install") ) == 0 )                        // Install
249                 {
250                         TCHAR desc[ 256 ];
251                         
252                         desc[ 0 ] = 0;
253                         LoadString( GetModuleHandle( NULL ), IDS_SERVICE_DESCRIPTION, desc, sizeof( desc ) );
254                         err = InstallService( kServiceName, kServiceName, desc, argv[0] );
255                         if( err )
256                         {
257                                 ReportStatus( EVENTLOG_ERROR_TYPE, "install service failed (%d)\n", err );
258                                 goto exit;
259                         }
260                 }
261                 else if( StrCmp( argv[ i ], TEXT("-remove") ) == 0 )            // Remove
262                 {
263                         err = RemoveService( kServiceName );
264                         if( err )
265                         {
266                                 ReportStatus( EVENTLOG_ERROR_TYPE, "remove service failed (%d)\n", err );
267                                 goto exit;
268                         }
269                 }
270                 else if( StrCmp( argv[ i ], TEXT("-start") ) == 0 )             // Start
271                 {
272                         start = TRUE;
273                 }
274                 else if( StrCmp( argv[ i ], TEXT("-server") ) == 0 )            // Server
275                 {
276                         err = RunDirect( argc, argv );
277                         if( err )
278                         {
279                                 ReportStatus( EVENTLOG_ERROR_TYPE, "run service directly failed (%d)\n", err );
280                         }
281                         goto exit;
282                 }
283                 else if( StrCmp( argv[ i ], TEXT("-q") ) == 0 )                 // Quiet Mode (toggle)
284                 {
285                         gServiceQuietMode = !gServiceQuietMode;
286                 }
287                 else if( ( StrCmp( argv[ i ], TEXT("-help") ) == 0 ) ||         // Help
288                                  ( StrCmp( argv[ i ], TEXT("-h") ) == 0 ) )
289                 {
290                         Usage();
291                         err = 0;
292                         break;
293                 }
294                 else
295                 {
296                         Usage();
297                         err = kParamErr;
298                         break;
299                 }
300         }
301         
302         // Start the service dispatcher if requested. This does not return until all services have terminated. If any 
303         // global initialization is needed, it should be done before starting the service dispatcher, but only if it 
304         // will take less than 30 seconds. Otherwise, use a separate thread for it and start the dispatcher immediately.
305         
306         if( start )
307         {
308                 ok = StartServiceCtrlDispatcher( gServiceDispatchTable );
309                 err = translate_errno( ok, (OSStatus) GetLastError(), kInUseErr );
310                 if( err != kNoErr )
311                 {
312                         ReportStatus( EVENTLOG_ERROR_TYPE, "start service dispatcher failed (%d)\n", err );
313                         goto exit;
314                 }
315         }
316         err = 0;
317         
318 exit:
319         dlog( kDebugLevelTrace, DEBUG_NAME "exited (%d %m)\n", err, err );
320         _CrtDumpMemoryLeaks();
321         return( (int) err );
322 }
323
324 //===========================================================================================================================
325 //      Usage
326 //===========================================================================================================================
327
328 static void     Usage( void )
329 {
330         fprintf( stderr, "\n" );
331         fprintf( stderr, "mDNSResponder 1.0d1\n" );
332         fprintf( stderr, "\n" );
333         fprintf( stderr, "    <no args>    Runs the service normally\n" );
334         fprintf( stderr, "    -install     Creates the service and starts it\n" );
335         fprintf( stderr, "    -remove      Stops the service and deletes it\n" );
336         fprintf( stderr, "    -start       Starts the service dispatcher after processing all other arguments\n" );
337         fprintf( stderr, "    -server      Runs the service directly as a server (for debugging)\n" );
338         fprintf( stderr, "    -q           Toggles Quiet Mode (no events or output)\n" );
339         fprintf( stderr, "    -remote      Allow remote connections\n" );
340         fprintf( stderr, "    -cache n     Number of mDNS cache entries (defaults to %d)\n", kDNSServiceCacheEntryCountDefault );
341         fprintf( stderr, "    -h[elp]      Display Help/Usage\n" );
342         fprintf( stderr, "\n" );
343 }
344
345 //===========================================================================================================================
346 //      ConsoleControlHandler
347 //===========================================================================================================================
348
349 static BOOL WINAPI      ConsoleControlHandler( DWORD inControlEvent )
350 {
351         BOOL                    handled;
352         OSStatus                err;
353         
354         handled = FALSE;
355         switch( inControlEvent )
356         {
357                 case CTRL_C_EVENT:
358                 case CTRL_BREAK_EVENT:
359                 case CTRL_CLOSE_EVENT:
360                 case CTRL_LOGOFF_EVENT:
361                 case CTRL_SHUTDOWN_EVENT:
362                         err = ServiceSpecificStop();
363                         require_noerr( err, exit );
364                         
365                         handled = TRUE;
366                         break;
367                 
368                 default:
369                         break;
370         }
371         
372 exit:
373         return( handled );
374 }
375
376 //===========================================================================================================================
377 //      InstallService
378 //===========================================================================================================================
379
380 static OSStatus InstallService( LPCTSTR inName, LPCTSTR inDisplayName, LPCTSTR inDescription, LPCTSTR inPath )
381 {
382         OSStatus                err;
383         SC_HANDLE               scm;
384         SC_HANDLE               service;
385         BOOL                    ok;
386         TCHAR                   fullPath[ MAX_PATH ];
387         TCHAR *                 namePtr;
388         DWORD                   size;
389         
390         scm             = NULL;
391         service = NULL;
392         
393         // Get a full path to the executable since a relative path may have been specified.
394         
395         size = GetFullPathName( inPath, MAX_PATH, fullPath, &namePtr );
396         err = translate_errno( size > 0, (OSStatus) GetLastError(), kPathErr );
397         require_noerr( err, exit );
398         
399         // Create the service and start it.
400         
401         scm = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
402         err = translate_errno( scm, (OSStatus) GetLastError(), kOpenErr );
403         require_noerr( err, exit );
404         
405         service = CreateService( scm, inName, inDisplayName, SERVICE_ALL_ACCESS, SERVICE_WIN32_SHARE_PROCESS, 
406                                                          SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, fullPath, NULL, NULL, kServiceDependencies, 
407                                                          NULL, NULL );
408         err = translate_errno( service, (OSStatus) GetLastError(), kDuplicateErr );
409         require_noerr( err, exit );
410
411         err = SetServiceParameters();
412         check_noerr( err );
413         
414         if( inDescription )
415         {
416                 err = SetServiceInfo( scm, inName, inDescription );
417                 check_noerr( err );
418         }
419
420         ok = StartService( service, 0, NULL );
421         err = translate_errno( ok, (OSStatus) GetLastError(), kInUseErr );
422         require_noerr( err, exit );
423         
424         ReportStatus( EVENTLOG_SUCCESS, "installed service \"%s\"/\"%s\" at \"%s\"\n", inName, inDisplayName, inPath );
425         err = kNoErr;
426         
427 exit:
428         if( service )
429         {
430                 CloseServiceHandle( service );
431         }
432         if( scm )
433         {
434                 CloseServiceHandle( scm );
435         }
436         return( err );
437 }
438
439 //===========================================================================================================================
440 //      RemoveService
441 //===========================================================================================================================
442
443 static OSStatus RemoveService( LPCTSTR inName )
444 {
445         OSStatus                        err;
446         SC_HANDLE                       scm;
447         SC_HANDLE                       service;
448         BOOL                            ok;
449         SERVICE_STATUS          status;
450         
451         scm             = NULL;
452         service = NULL;
453         
454         // Open a connection to the service.
455         
456         scm = OpenSCManager( 0, 0, SC_MANAGER_ALL_ACCESS );
457         err = translate_errno( scm, (OSStatus) GetLastError(), kOpenErr );
458         require_noerr( err, exit );
459         
460         service = OpenService( scm, inName, SERVICE_STOP | SERVICE_QUERY_STATUS | DELETE );
461         err = translate_errno( service, (OSStatus) GetLastError(), kNotFoundErr );
462         require_noerr( err, exit );
463         
464         // Stop the service, if it is not already stopped, then delete it.
465         
466         ok = QueryServiceStatus( service, &status );
467         err = translate_errno( ok, (OSStatus) GetLastError(), kAuthenticationErr );
468         require_noerr( err, exit );
469         
470         if( status.dwCurrentState != SERVICE_STOPPED )
471         {
472                 ok = ControlService( service, SERVICE_CONTROL_STOP, &status );
473                 check_translated_errno( ok, (OSStatus) GetLastError(), kAuthenticationErr );
474         }
475         
476         ok = DeleteService( service );
477         err = translate_errno( ok, (OSStatus) GetLastError(), kDeletedErr );
478         require_noerr( err, exit );
479                 
480         ReportStatus( EVENTLOG_SUCCESS, "Removed service \"%s\"\n", inName );
481         err = ERROR_SUCCESS;
482         
483 exit:
484         if( service )
485         {
486                 CloseServiceHandle( service );
487         }
488         if( scm )
489         {
490                 CloseServiceHandle( scm );
491         }
492         return( err );
493 }
494
495
496
497 //===========================================================================================================================
498 //      SetServiceParameters
499 //===========================================================================================================================
500
501 static OSStatus SetServiceParameters()
502 {
503         DWORD                   value;
504         DWORD                   valueLen = sizeof(DWORD);
505         DWORD                   type;
506         OSStatus                err;
507         HKEY                    key;
508
509         key = NULL;
510
511         //
512         // Add/Open Parameters section under service entry in registry
513         //
514         err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode, &key );
515         require_noerr( err, exit );
516         
517         //
518         // If the value isn't already there, then we create it
519         //
520         err = RegQueryValueEx(key, kServiceManageLLRouting, 0, &type, (LPBYTE) &value, &valueLen);
521
522         if (err != ERROR_SUCCESS)
523         {
524                 value = 1;
525
526                 err = RegSetValueEx( key, kServiceManageLLRouting, 0, REG_DWORD, (const LPBYTE) &value, sizeof(DWORD) );
527                 require_noerr( err, exit );
528         }
529
530 exit:
531
532         if ( key )
533         {
534                 RegCloseKey( key );
535         }
536
537         return( err );
538 }
539
540
541
542 //===========================================================================================================================
543 //      GetServiceParameters
544 //===========================================================================================================================
545
546 static OSStatus GetServiceParameters()
547 {
548         DWORD                   value;
549         DWORD                   valueLen;
550         DWORD                   type;
551         OSStatus                err;
552         HKEY                    key;
553
554         key = NULL;
555
556         //
557         // Add/Open Parameters section under service entry in registry
558         //
559         err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode, &key );
560         require_noerr( err, exit );
561         
562         valueLen = sizeof(DWORD);
563         err = RegQueryValueEx(key, kServiceManageLLRouting, 0, &type, (LPBYTE) &value, &valueLen);
564         if (err == ERROR_SUCCESS)
565         {
566                 gServiceManageLLRouting = (value) ? true : false;
567         }
568
569         valueLen = sizeof(DWORD);
570         err = RegQueryValueEx(key, kServiceCacheEntryCount, 0, &type, (LPBYTE) &value, &valueLen);
571         if (err == ERROR_SUCCESS)
572         {
573                 gServiceCacheEntryCount = value;
574         }
575
576 exit:
577
578         if ( key )
579         {
580                 RegCloseKey( key );
581         }
582
583         return( err );
584 }
585
586
587 //===========================================================================================================================
588 //      CheckFirewall
589 //===========================================================================================================================
590
591 static OSStatus CheckFirewall()
592 {
593         DWORD                                   value;
594         DWORD                                   valueLen;
595         DWORD                                   type;
596         ENUM_SERVICE_STATUS     *       lpService = NULL;
597         SC_HANDLE                               sc = NULL;
598         HKEY                                    key = NULL;
599         BOOL                                    ok;
600         DWORD                                   bytesNeeded = 0;
601         DWORD                                   srvCount;
602         DWORD                                   resumeHandle = 0;
603         DWORD                                   srvType;
604         DWORD                                   srvState;
605         DWORD                                   dwBytes = 0;
606         DWORD                                   i;
607         BOOL                                    isRunning = FALSE;
608         OSStatus                                err = kUnknownErr;
609         
610         // Check to see if the firewall service is running.  If it isn't, then
611         // we want to return immediately
612
613         sc = OpenSCManager( NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE );
614         err = translate_errno( sc, GetLastError(), kUnknownErr );
615         require_noerr( err, exit );
616
617         srvType         =       SERVICE_WIN32;
618         srvState        =       SERVICE_STATE_ALL;
619
620         for ( ;; )
621         {
622                 // Call EnumServicesStatus using the handle returned by OpenSCManager
623
624                 ok = EnumServicesStatus ( sc, srvType, srvState, lpService, dwBytes, &bytesNeeded, &srvCount, &resumeHandle );
625
626                 if ( ok || ( GetLastError() != ERROR_MORE_DATA ) )
627                 {
628                         break;
629                 }
630
631                 if ( lpService )
632                 {
633                         free( lpService );
634                 }
635
636                 dwBytes = bytesNeeded;
637
638                 lpService = ( ENUM_SERVICE_STATUS* ) malloc( dwBytes );
639                 require_action( lpService, exit, err = mStatus_NoMemoryErr );
640         }
641
642         err = translate_errno( ok, GetLastError(), kUnknownErr );
643         require_noerr( err, exit );
644
645         for ( i = 0; i < srvCount; i++ )
646         {
647                 if ( wcscmp( lpService[i].lpServiceName, L"SharedAccess" ) == 0 )
648                 {
649                         if ( lpService[i].ServiceStatus.dwCurrentState == SERVICE_RUNNING )
650                         {
651                                 isRunning = TRUE;
652                         }
653
654                         break;
655                 }
656         }
657
658         require_action( isRunning, exit, err = kUnknownErr );
659
660         // Check to see if we've managed the firewall.
661         // This package might have been installed, then
662         // the OS was upgraded to SP2 or above.  If that's
663         // the case, then we need to manipulate the firewall
664         // so networking works correctly.
665
666         err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode, &key );
667         require_noerr( err, exit );
668
669         valueLen = sizeof(DWORD);
670         err = RegQueryValueEx(key, kServiceManageFirewall, 0, &type, (LPBYTE) &value, &valueLen);
671         
672         if ((err != ERROR_SUCCESS) || (value == 0))
673         {
674                 wchar_t fullPath[ MAX_PATH ];
675                 DWORD   size;
676
677                 // Get a full path to the executable
678
679                 size = GetModuleFileNameW( NULL, fullPath, MAX_PATH );
680                 err = translate_errno( size > 0, (OSStatus) GetLastError(), kPathErr );
681                 require_noerr( err, exit );
682
683                 err = mDNSAddToFirewall(fullPath, kServiceFirewallName);
684                 require_noerr( err, exit );
685
686                 value = 1;
687                 err = RegSetValueEx( key, kServiceManageFirewall, 0, REG_DWORD, (const LPBYTE) &value, sizeof( DWORD ) );
688                 require_noerr( err, exit );
689         }
690         
691 exit:
692
693         if ( key )
694         {
695                 RegCloseKey( key );
696         }
697         
698         if ( lpService )
699         {
700                 free( lpService );
701         }
702
703         if ( sc )
704         {
705                 CloseServiceHandle ( sc );
706         }
707
708         return( err );
709 }
710
711
712
713 //===========================================================================================================================
714 //      SetServiceInfo
715 //===========================================================================================================================
716
717 static OSStatus SetServiceInfo( SC_HANDLE inSCM, LPCTSTR inServiceName, LPCTSTR inDescription )
718 {
719         OSStatus                                err;
720         SC_LOCK                                 lock;
721         SC_HANDLE                               service;
722         SERVICE_DESCRIPTION             description;
723         SERVICE_FAILURE_ACTIONS actions;
724         SC_ACTION                               action;
725         BOOL                                    ok;
726         
727         check( inServiceName );
728         check( inDescription );
729         
730         lock    = NULL;
731         service = NULL;
732         
733         // Open the database (if not provided) and lock it to prevent other access while re-configuring.
734         
735         if( !inSCM )
736         {
737                 inSCM = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
738                 err = translate_errno( inSCM, (OSStatus) GetLastError(), kOpenErr );
739                 require_noerr( err, exit );
740         }
741         
742         lock = LockServiceDatabase( inSCM );
743         err = translate_errno( lock, (OSStatus) GetLastError(), kInUseErr );
744         require_noerr( err, exit );
745         
746         // Open a handle to the service. 
747
748         service = OpenService( inSCM, inServiceName, SERVICE_CHANGE_CONFIG|SERVICE_START );
749         err = translate_errno( service, (OSStatus) GetLastError(), kNotFoundErr );
750         require_noerr( err, exit );
751         
752         // Change the description.
753         
754         description.lpDescription = (LPTSTR) inDescription;
755         ok = ChangeServiceConfig2( service, SERVICE_CONFIG_DESCRIPTION, &description );
756         err = translate_errno( ok, (OSStatus) GetLastError(), kParamErr );
757         require_noerr( err, exit );
758         
759         actions.dwResetPeriod   =       INFINITE;
760         actions.lpRebootMsg             =       NULL;
761         actions.lpCommand               =       NULL;
762         actions.cActions                =       1;
763         actions.lpsaActions             =       &action;
764         action.Delay                    =       500;
765         action.Type                             =       SC_ACTION_RESTART;
766
767         ok = ChangeServiceConfig2( service, SERVICE_CONFIG_FAILURE_ACTIONS, &actions );
768         err = translate_errno( ok, (OSStatus) GetLastError(), kParamErr );
769         require_noerr( err, exit );
770         
771         err = ERROR_SUCCESS;
772         
773 exit:
774         // Close the service and release the lock.
775         
776         if( service )
777         {
778                 CloseServiceHandle( service );
779         }
780         if( lock )
781         {
782                 UnlockServiceDatabase( lock ); 
783         }
784         return( err );
785 }
786
787 //===========================================================================================================================
788 //      ReportStatus
789 //===========================================================================================================================
790
791 static void     ReportStatus( int inType, const char *inFormat, ... )
792 {
793         if( !gServiceQuietMode )
794         {
795                 va_list         args;
796                 
797                 va_start( args, inFormat );
798                 if( gServiceEventSource )
799                 {
800                         char                            s[ 1024 ];
801                         BOOL                            ok;
802                         const char *            array[ 1 ];
803                         
804                         vsprintf( s, inFormat, args );
805                         array[ 0 ] = s;
806                         ok = ReportEventA( gServiceEventSource, (WORD) inType, 0, 0x20000001L, NULL, 1, 0, array, NULL );
807                         check_translated_errno( ok, GetLastError(), kUnknownErr );
808                 }
809                 else
810                 {
811                         int             n;
812                         
813                         n = vfprintf( stderr, inFormat, args );
814                         check( n >= 0 );
815                 }
816                 va_end( args );
817         }
818 }
819
820 //===========================================================================================================================
821 //      RunDirect
822 //===========================================================================================================================
823
824 int     RunDirect( int argc, LPTSTR argv[] )
825 {
826         OSStatus                err;
827         BOOL                    initialized;
828    BOOL        ok;
829         
830         initialized = FALSE;
831
832         // Install a Console Control Handler to handle things like control-c signals.
833         
834         ok = SetConsoleCtrlHandler( ConsoleControlHandler, TRUE );
835         err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
836         require_noerr( err, exit );
837         
838         err = ServiceSpecificInitialize( argc, argv );
839         require_noerr( err, exit );
840         initialized = TRUE;
841         
842         // Run the service. This does not return until the service quits or is stopped.
843         
844         ReportStatus( EVENTLOG_SUCCESS, "Running \"%s\" service directly\n", kServiceName );
845         
846         err = ServiceSpecificRun( argc, argv );
847         require_noerr( err, exit );
848         
849         // Clean up.
850         
851 exit:
852         if( initialized )
853         {
854                 ServiceSpecificFinalize( argc, argv );
855         }
856         return( err );
857 }
858
859 #if 0
860 #pragma mark -
861 #endif
862
863 //===========================================================================================================================
864 //      ServiceMain
865 //===========================================================================================================================
866
867 static void WINAPI ServiceMain( DWORD argc, LPTSTR argv[] )
868 {
869         OSStatus                err;
870         BOOL                    ok;
871         
872         err = ServiceSetupEventLogging();
873         check_noerr( err );
874
875         err = GetServiceParameters();
876         check_noerr( err );
877         
878         // Initialize the service status and register the service control handler with the name of the service.
879         
880         gServiceStatus.dwServiceType                            = SERVICE_WIN32_SHARE_PROCESS;
881         gServiceStatus.dwCurrentState                           = 0;
882         gServiceStatus.dwControlsAccepted                       = SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_POWEREVENT;
883         gServiceStatus.dwWin32ExitCode                          = NO_ERROR;
884         gServiceStatus.dwServiceSpecificExitCode        = NO_ERROR;
885         gServiceStatus.dwCheckPoint                             = 0;
886         gServiceStatus.dwWaitHint                                       = 0;
887         
888         gServiceStatusHandle = RegisterServiceCtrlHandlerEx( argv[ 0 ], ServiceControlHandler, NULL );
889         err = translate_errno( gServiceStatusHandle, (OSStatus) GetLastError(), kInUseErr );
890         require_noerr( err, exit );
891         
892         // Mark the service as starting.
893
894         gServiceStatus.dwCurrentState   = SERVICE_START_PENDING;
895         gServiceStatus.dwCheckPoint             = 0;
896         gServiceStatus.dwWaitHint               = 5000; // 5 seconds
897         ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
898         check_translated_errno( ok, GetLastError(), kParamErr );
899         
900         // Run the service. This does not return until the service quits or is stopped.
901         
902         err = ServiceRun( (int) argc, argv );
903         if( err != kNoErr )
904         {
905                 gServiceStatus.dwWin32ExitCode                          = ERROR_SERVICE_SPECIFIC_ERROR;
906                 gServiceStatus.dwServiceSpecificExitCode        = (DWORD) err;
907         }
908         
909         // Service-specific work is done so mark the service as stopped.
910         
911         gServiceStatus.dwCurrentState = SERVICE_STOPPED;
912         ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
913         check_translated_errno( ok, GetLastError(), kParamErr );
914         
915         // Note: The service status handle should not be closed according to Microsoft documentation.
916         
917 exit:
918         if( gServiceEventSource )
919         {
920                 ok = DeregisterEventSource( gServiceEventSource );
921                 check_translated_errno( ok, GetLastError(), kUnknownErr );
922                 gServiceEventSource = NULL;
923         }
924 }
925
926 //===========================================================================================================================
927 //      ServiceSetupEventLogging
928 //===========================================================================================================================
929
930 static OSStatus ServiceSetupEventLogging( void )
931 {
932         OSStatus                        err;
933         HKEY                            key;
934         LPCTSTR                         s;
935         DWORD                           typesSupported;
936         TCHAR                           path[ MAX_PATH ];
937         DWORD                           n;
938         
939         key = NULL;
940         
941         // Add/Open source name as a sub-key under the Application key in the EventLog registry key.
942
943         s = TEXT("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\") kServiceName;
944         err = RegCreateKey( HKEY_LOCAL_MACHINE, s, &key );
945         require_noerr( err, exit );
946         
947         // Add the name to the EventMessageFile subkey.
948
949         path[ 0 ] = '\0';
950         GetModuleFileName( NULL, path, MAX_PATH );
951         n = (DWORD) ( ( StrLen( path ) + 1 ) * sizeof( TCHAR ) );
952         err = RegSetValueEx( key, TEXT("EventMessageFile"), 0, REG_EXPAND_SZ, (const LPBYTE) path, n );
953         require_noerr( err, exit );
954         
955         // Set the supported event types in the TypesSupported subkey.
956         
957         typesSupported = 0 
958                                          | EVENTLOG_SUCCESS
959                                          | EVENTLOG_ERROR_TYPE
960                                          | EVENTLOG_WARNING_TYPE
961                                          | EVENTLOG_INFORMATION_TYPE
962                                          | EVENTLOG_AUDIT_SUCCESS
963                                          | EVENTLOG_AUDIT_FAILURE; 
964         err = RegSetValueEx( key, TEXT("TypesSupported"), 0, REG_DWORD, (const LPBYTE) &typesSupported, sizeof( DWORD ) );
965         require_noerr( err, exit );
966         
967         // Set up the event source.
968         
969         gServiceEventSource = RegisterEventSource( NULL, kServiceName );
970         err = translate_errno( gServiceEventSource, (OSStatus) GetLastError(), kParamErr );
971         require_noerr( err, exit );
972                 
973 exit:
974         if( key )
975         {
976                 RegCloseKey( key );
977         }
978         return( err );
979 }
980
981 //===========================================================================================================================
982 //      HandlePowerSuspend
983 //===========================================================================================================================
984
985 static void HandlePowerSuspend( void * v )
986 {
987         LARGE_INTEGER   timeout;
988         BOOL                    ok;
989
990         ( void ) v;
991
992         dlog( kDebugLevelInfo, DEBUG_NAME "HandlePowerSuspend\n" );
993
994         gMDNSRecord.SystemWakeOnLANEnabled = SystemWakeForNetworkAccess( &timeout );
995                                 
996         if ( gMDNSRecord.SystemWakeOnLANEnabled )
997         {
998                 ok = SetWaitableTimer( gSPSWakeupEvent, &timeout, 0, NULL, NULL, TRUE );
999                 check( ok );
1000         }
1001
1002         mDNSCoreMachineSleep(&gMDNSRecord, TRUE);
1003 }
1004
1005
1006 //===========================================================================================================================
1007 //      HandlePowerResumeSuspend
1008 //===========================================================================================================================
1009
1010 static void HandlePowerResumeSuspend( void * v )
1011 {
1012         ( void ) v;
1013
1014         dlog( kDebugLevelInfo, DEBUG_NAME "HandlePowerResumeSuspend\n" );
1015
1016         if ( gSPSWakeupEvent )
1017         {
1018                 CancelWaitableTimer( gSPSWakeupEvent );
1019         }
1020
1021         if ( gSPSSleepEvent )
1022         {
1023                 CancelWaitableTimer( gSPSSleepEvent );
1024         }
1025
1026         mDNSCoreMachineSleep(&gMDNSRecord, FALSE);
1027 }
1028
1029
1030 //===========================================================================================================================
1031 //      ServiceControlHandler
1032 //===========================================================================================================================
1033
1034 static DWORD WINAPI     ServiceControlHandler( DWORD inControl, DWORD inEventType, LPVOID inEventData, LPVOID inContext )
1035 {
1036         BOOL            setStatus;
1037         BOOL            ok;
1038
1039         DEBUG_UNUSED( inEventData );
1040         DEBUG_UNUSED( inContext );
1041         
1042         setStatus = TRUE;
1043         switch( inControl )
1044         {
1045                 case SERVICE_CONTROL_STOP:
1046                         dlog( kDebugLevelInfo, DEBUG_NAME "ServiceControlHandler: SERVICE_CONTROL_STOP\n" );
1047                         
1048                         ServiceStop();
1049                         setStatus = FALSE;
1050                         break;
1051                 
1052                 case SERVICE_CONTROL_POWEREVENT:
1053
1054                         if (inEventType == PBT_APMSUSPEND)
1055                         {
1056                                 dlog( kDebugLevelInfo, DEBUG_NAME "ServiceControlHandler: PBT_APMSUSPEND\n" );
1057
1058                                 QueueUserAPC( ( PAPCFUNC ) HandlePowerSuspend, gMDNSRecord.p->mainThread, ( ULONG_PTR ) NULL );
1059                         }
1060                         else if (inEventType == PBT_APMRESUMESUSPEND)
1061                         {
1062                                 dlog( kDebugLevelInfo, DEBUG_NAME "ServiceControlHandler: PBT_APMRESUMESUSPEND\n" );
1063
1064                                 QueueUserAPC( ( PAPCFUNC ) HandlePowerResumeSuspend, gMDNSRecord.p->mainThread, ( ULONG_PTR ) NULL );
1065                         }
1066                 
1067                         break;
1068
1069                 default:
1070                         dlog( kDebugLevelNotice, DEBUG_NAME "ServiceControlHandler: event (0x%08X)\n", inControl );
1071                         break;
1072         }
1073         
1074         if( setStatus && gServiceStatusHandle )
1075         {
1076                 ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
1077                 check_translated_errno( ok, GetLastError(), kUnknownErr );
1078         }
1079
1080         return NO_ERROR;
1081 }
1082
1083 //===========================================================================================================================
1084 //      ServiceRun
1085 //===========================================================================================================================
1086
1087 static OSStatus ServiceRun( int argc, LPTSTR argv[] )
1088 {
1089         OSStatus                err;
1090         BOOL                    initialized;
1091         BOOL                    ok;
1092         
1093         DEBUG_UNUSED( argc );
1094         DEBUG_UNUSED( argv );
1095         
1096         initialized = FALSE;
1097         
1098         // <rdar://problem/5727548> Make the service as running before we call ServiceSpecificInitialize. We've
1099         // had reports that some machines with McAfee firewall installed cause a problem with iTunes installation.
1100         // We think that the firewall product is interferring with code in ServiceSpecificInitialize. So as a
1101         // simple workaround, we'll mark us as running *before* we call ServiceSpecificInitialize. This will unblock
1102         // any installers that are waiting for our state to change.
1103
1104         gServiceStatus.dwCurrentState = SERVICE_RUNNING;
1105         ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
1106         check_translated_errno( ok, GetLastError(), kParamErr );
1107
1108         // Initialize the service-specific stuff
1109         
1110         err = ServiceSpecificInitialize( argc, argv );
1111         require_noerr( err, exit );
1112         initialized = TRUE;
1113         
1114         err = CheckFirewall();
1115         check_noerr( err );
1116
1117         if ( err )
1118         {
1119                 gRetryFirewall = TRUE;
1120         }
1121         
1122         // Run the service-specific stuff. This does not return until the service quits or is stopped.
1123         
1124         ReportStatus( EVENTLOG_INFORMATION_TYPE, "mDNSResponder started\n" );
1125         err = ServiceSpecificRun( argc, argv );
1126         ReportStatus( EVENTLOG_INFORMATION_TYPE, "mDNSResponder stopped (%d)\n", err );
1127         require_noerr( err, exit );
1128         
1129         // Service stopped. Clean up and we're done.
1130         
1131 exit:
1132         if( initialized )
1133         {
1134                 ServiceSpecificFinalize( argc, argv );
1135         }
1136         return( err );
1137 }
1138
1139 //===========================================================================================================================
1140 //      ServiceStop
1141 //===========================================================================================================================
1142
1143 static void     ServiceStop( void )
1144 {
1145         BOOL                    ok;
1146         OSStatus                err;
1147         
1148         // Signal the event to cause the service to exit.
1149         
1150         if( gServiceStatusHandle )
1151         {
1152                 gServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
1153                 ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
1154                 check_translated_errno( ok, GetLastError(), kParamErr );
1155         }
1156                 
1157         err = ServiceSpecificStop();
1158         check_noerr( err );
1159 }
1160
1161 #if 0
1162 #pragma mark -
1163 #pragma mark == Service Specific ==
1164 #endif
1165
1166 //===========================================================================================================================
1167 //      ServiceSpecificInitialize
1168 //===========================================================================================================================
1169
1170 static OSStatus ServiceSpecificInitialize( int argc, LPTSTR argv[] )
1171 {
1172         OSVERSIONINFO osInfo;
1173         OSStatus err;
1174         BOOL ok;
1175         
1176         DEBUG_UNUSED( argc );
1177         DEBUG_UNUSED( argv );
1178         
1179         mDNSPlatformMemZero( &gMDNSRecord, sizeof gMDNSRecord);
1180         mDNSPlatformMemZero( &gPlatformStorage, sizeof gPlatformStorage);
1181
1182         gPlatformStorage.registerWaitableEventFunc = RegisterWaitableEvent;
1183         gPlatformStorage.unregisterWaitableEventFunc = UnregisterWaitableEvent;
1184
1185         err = mDNS_Init( &gMDNSRecord, &gPlatformStorage, gRRCache, RR_CACHE_SIZE, mDNS_Init_AdvertiseLocalAddresses, CoreCallback, mDNS_Init_NoInitCallbackContext); 
1186         require_noerr( err, exit);
1187
1188         err = SetupNotifications();
1189         check_noerr( err );
1190
1191         err = udsserver_init(mDNSNULL, 0);
1192         require_noerr( err, exit);
1193
1194         //
1195         // Get the version of Windows that we're running on
1196         //
1197         osInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
1198         ok = GetVersionEx( &osInfo );
1199         err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
1200         require_noerr( err, exit );
1201         gOSMajorVersion = osInfo.dwMajorVersion;
1202         gOSMinorVersion = osInfo.dwMinorVersion;
1203
1204         SetLLRoute( &gMDNSRecord );
1205
1206 exit:
1207         if( err != kNoErr )
1208         {
1209                 ServiceSpecificFinalize( argc, argv );
1210         }
1211         return( err );
1212 }
1213
1214 //===========================================================================================================================
1215 //      ServiceSpecificRun
1216 //===========================================================================================================================
1217
1218 static OSStatus ServiceSpecificRun( int argc, LPTSTR argv[] )
1219 {
1220         HANDLE  *       waitList;
1221         int                     waitListCount;
1222         DWORD           timeout;
1223         DWORD           result;
1224         BOOL            done;
1225         mStatus         err;
1226         
1227         DEBUG_UNUSED( argc );
1228         DEBUG_UNUSED( argv );
1229
1230         timeout = ( gRetryFirewall ) ? kRetryFirewallPeriod : INFINITE;
1231
1232         err = SetupInterfaceList( &gMDNSRecord );
1233         check( !err );
1234
1235         err = uDNS_SetupDNSConfig( &gMDNSRecord );
1236         check( !err );
1237
1238         done = FALSE;
1239
1240         // Main event loop.
1241
1242         while( !done )
1243         {
1244                 waitList                = NULL;
1245                 waitListCount   = 0;
1246
1247                 err = SetupWaitList( &gMDNSRecord, &waitList, &waitListCount );
1248                 require_noerr( err, exit );
1249
1250                 gEventSourceListChanged = FALSE;
1251
1252                 for ( ;; )
1253                 {
1254                         mDNSs32 interval;
1255
1256                         if ( gEventSourceListChanged )
1257                         {
1258                                 break;
1259                         }
1260
1261                         // Give the mDNS core a chance to do its work and determine next event time.
1262                         
1263                         interval = mDNS_Execute( &gMDNSRecord ) - mDNS_TimeNow( &gMDNSRecord );
1264                         interval = udsserver_idle( interval );
1265
1266                         if      (interval < 0)                                          interval = 0;
1267                         else if (interval > (0x7FFFFFFF / 1000))        interval = 0x7FFFFFFF / mDNSPlatformOneSecond;
1268                         else                                                                            interval = (interval * 1000) / mDNSPlatformOneSecond;
1269                         
1270                         // Wait until something occurs (e.g. cancel, incoming packet, or timeout).
1271                                                 
1272                         result = WaitForMultipleObjectsEx( ( DWORD ) waitListCount, waitList, FALSE, (DWORD) interval, TRUE );
1273                         check( result != WAIT_FAILED );
1274
1275                         if ( result != WAIT_FAILED )
1276                         {
1277                                 if ( result == WAIT_TIMEOUT )
1278                                 {
1279                                         // Next task timeout occurred. Loop back up to give mDNS core a chance to work.
1280                                         
1281                                         dlog( kDebugLevelChatty - 1, DEBUG_NAME "timeout\n" );
1282                                         continue;
1283                                 }
1284                                 else if ( result == WAIT_IO_COMPLETION )
1285                                 {
1286                                         dlog( kDebugLevelChatty - 1, DEBUG_NAME "i/o completion\n" );
1287                                         continue;
1288                                 }
1289                                 else if ( result == kWaitListStopEvent )
1290                                 {
1291                                         // Stop event. Set the done flag and break to exit.
1292                                         
1293                                         dlog( kDebugLevelVerbose, DEBUG_NAME "stopping...\n" );
1294                                         done = TRUE;
1295                                         break;
1296                                 }
1297                                 else if( result == kWaitListInterfaceListChangedEvent )
1298                                 {
1299                                         int             inBuffer;
1300                                         int             outBuffer;
1301                                         DWORD   outSize;
1302
1303                                         // It would be nice to come up with a more elegant solution to this, but it seems that
1304                                         // GetAdaptersAddresses doesn't always stay in sync after network changed events.  So as
1305                                         // as a simple workaround, we'll pause for a couple of seconds before processing the change.
1306
1307                                         // We arrived at 2 secs by trial and error. We could reproduce the problem after sleeping
1308                                         // for 500 msec and 750 msec, but couldn't after sleeping for 1 sec.  We added another
1309                                         // second on top of that to account for machine load or some other exigency.
1310
1311                                         Sleep( 2000 );
1312
1313                                         // Interface list changed event. Break out of the inner loop to re-setup the wait list.
1314                                         
1315                                         InterfaceListDidChange( &gMDNSRecord );
1316
1317                                         // reset the event handler
1318                                         inBuffer        = 0;
1319                                         outBuffer       = 0;
1320                                         err = WSAIoctl( gInterfaceListChangedSocket, SIO_ADDRESS_LIST_CHANGE, &inBuffer, 0, &outBuffer, 0, &outSize, NULL, NULL );
1321                                         if( err < 0 )
1322                                         {
1323                                                 check( errno_compat() == WSAEWOULDBLOCK );
1324                                         }
1325                                 }
1326                                 else if ( result == kWaitListComputerDescriptionEvent )
1327                                 {
1328                                         // The computer description might have changed
1329                                         
1330                                         ComputerDescriptionDidChange( &gMDNSRecord );
1331
1332                                         udsserver_handle_configchange( &gMDNSRecord );
1333
1334                                         // and reset the event handler
1335                                         if ( ( gDescKey != NULL ) && ( gDescChangedEvent != NULL ) )
1336                                         {
1337                                                 err = RegNotifyChangeKeyValue( gDescKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET, gDescChangedEvent, TRUE);
1338                                                 check_noerr( err );
1339                                         }
1340                                 }
1341                                 else if ( result == kWaitListTCPIPEvent )
1342                                 {       
1343                                         // The TCP/IP might have changed
1344
1345                                         TCPIPConfigDidChange( &gMDNSRecord );
1346
1347                                         // and reset the event handler
1348
1349                                         if ( ( gTcpipKey != NULL ) && ( gTcpipChangedEvent ) )
1350                                         {
1351                                                 err = RegNotifyChangeKeyValue( gTcpipKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gTcpipChangedEvent, TRUE );
1352                                                 check_noerr( err );
1353                                         }
1354                                 }
1355                                 else if ( result == kWaitListDynDNSEvent )
1356                                 {
1357                                         // The DynDNS config might have changed
1358
1359                                         DynDNSConfigDidChange( &gMDNSRecord );
1360
1361                                         // and reset the event handler
1362
1363                                         if ((gDdnsKey != NULL) && (gDdnsChangedEvent))
1364                                         {
1365                                                 err = RegNotifyChangeKeyValue(gDdnsKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gDdnsChangedEvent, TRUE);
1366                                                 check_noerr( err );
1367                                         }
1368                                 }
1369                                 else if ( result == kWaitListFileShareEvent )
1370                                 {
1371                                         // File sharing changed
1372
1373                                         FileSharingDidChange( &gMDNSRecord );
1374
1375                                         // and reset the event handler
1376
1377                                         if ((gFileSharingKey != NULL) && (gFileSharingChangedEvent))
1378                                         {
1379                                                 err = RegNotifyChangeKeyValue(gFileSharingKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gFileSharingChangedEvent, TRUE);
1380                                                 check_noerr( err );
1381                                         }
1382                                 }
1383                                 else if ( result == kWaitListFirewallEvent )
1384                                 {
1385                                         // Firewall configuration changed
1386
1387                                         FirewallDidChange( &gMDNSRecord );
1388
1389                                         // and reset the event handler
1390
1391                                         if ((gFirewallKey != NULL) && (gFirewallChangedEvent))
1392                                         {
1393                                                 err = RegNotifyChangeKeyValue(gFirewallKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gFirewallChangedEvent, TRUE);
1394                                                 check_noerr( err );
1395                                         }
1396                                 }
1397                                 else if ( result == kWaitListSPSWakeupEvent )
1398                                 {
1399                                         __int64         temp;\r
1400                                         LARGE_INTEGER   timeout;\r
1401 \r
1402                                         dlog( kDebugLevelInfo, DEBUG_NAME "setting suspend event\n" );\r
1403 \r
1404                                         // Stay awake for 60 seconds\r
1405 \r
1406                                         temp                = -60 * 10000000;\r
1407                                         timeout.LowPart     = (DWORD) ( temp & 0xFFFFFFFF );\r
1408                                         timeout.HighPart    = (LONG)  ( temp >> 32 );\r
1409 \r
1410                                         SetWaitableTimer( gSPSSleepEvent, &timeout, 0, NULL, NULL, TRUE );
1411                                 }
1412                                 else if ( result == kWaitListSPSSleepEvent )
1413                                 {
1414                                         dlog( kDebugLevelInfo, DEBUG_NAME "suspending machine\n" );\r
1415                                         SetSuspendState( FALSE, FALSE, FALSE );
1416                                 }
1417                                 else
1418                                 {
1419                                         int waitItemIndex;
1420
1421                                         waitItemIndex = (int)( ( (int) result ) - WAIT_OBJECT_0 );
1422                                         dlog( kDebugLevelChatty, DEBUG_NAME "waitable event on %d\n", waitItemIndex );
1423                                         check( ( waitItemIndex >= 0 ) && ( waitItemIndex < waitListCount ) );
1424
1425                                         if ( ( waitItemIndex >= 0 ) && ( waitItemIndex < waitListCount ) )
1426                                         {
1427                                                 HANDLE                  signaledEvent;
1428                                                 EventSource     *       source;
1429                                                 int                             n = 0;
1430                                                 
1431                                                 signaledEvent = waitList[ waitItemIndex ];
1432
1433                                                 for ( source = gEventSourceList; source; source = source->next )
1434                                                 {
1435                                                         if ( source->event == signaledEvent )
1436                                                         {
1437                                                                 source->handler( &gMDNSRecord, source->event, source->context );
1438                                                                 ++n;
1439                                                                 break;
1440                                                         }
1441                                                 }
1442
1443                                                 check( n > 0 );
1444                                         }
1445                                         else
1446                                         {
1447                                                 dlog( kDebugLevelWarning, DEBUG_NAME "%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__, result );
1448                                         }
1449                                 }
1450                         }
1451                         else
1452                         {
1453                                 Sleep( 3 * 1000 );
1454                                 
1455                                 err = SetupInterfaceList( &gMDNSRecord );
1456                                 check( !err );
1457
1458                                 err = uDNS_SetupDNSConfig( &gMDNSRecord );
1459                                 check( !err );
1460                                 
1461                                 break;
1462                         }
1463                 }
1464
1465                 if ( waitList )
1466                 {
1467                         free( waitList );
1468                         waitList = NULL;
1469                         waitListCount = 0;
1470                 }
1471         }
1472
1473 exit:
1474
1475         return( 0 );
1476 }
1477
1478 //===========================================================================================================================
1479 //      ServiceSpecificStop
1480 //===========================================================================================================================
1481
1482 static OSStatus ServiceSpecificStop( void )
1483 {
1484         OSStatus        err;
1485         BOOL            ok;
1486
1487         ok = SetEvent(gStopEvent);
1488         err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
1489         require_noerr( err, exit );
1490 exit:
1491         return( err );
1492 }
1493
1494 //===========================================================================================================================
1495 //      ServiceSpecificFinalize
1496 //===========================================================================================================================
1497
1498 static void     ServiceSpecificFinalize( int argc, LPTSTR argv[] )
1499 {
1500         DEBUG_UNUSED( argc );
1501         DEBUG_UNUSED( argv );
1502         
1503         //
1504         // clean up any open sessions
1505         //
1506         while ( gEventSourceList )
1507         {
1508                 UnregisterWaitableEvent( &gMDNSRecord, gEventSourceList->event );
1509         }
1510
1511         //
1512         // give a chance for the udsserver code to clean up
1513         //
1514         udsserver_exit();
1515
1516         //
1517         // close down the mDNSCore
1518         //
1519         mDNS_Close(&gMDNSRecord);
1520
1521         //
1522         // clean up the notifications
1523         //
1524         TearDownNotifications();
1525
1526         //
1527         // clean up loaded library
1528         //
1529
1530         if( gIPHelperLibraryInstance )
1531         {
1532                 gGetIpInterfaceEntryFunctionPtr = NULL;
1533                 
1534                 FreeLibrary( gIPHelperLibraryInstance );
1535                 gIPHelperLibraryInstance = NULL;
1536         }
1537 }
1538
1539
1540 //===========================================================================================================================
1541 //      SetupNotifications
1542 //===========================================================================================================================
1543
1544 mDNSlocal mStatus       SetupNotifications()
1545 {
1546         mStatus                         err;
1547         SocketRef                       sock;
1548         unsigned long           param;
1549         int                                     inBuffer;
1550         int                                     outBuffer;
1551         DWORD                           outSize;
1552         
1553         gStopEvent      =       CreateEvent(NULL, FALSE, FALSE, NULL);
1554         err = translate_errno( gStopEvent, errno_compat(), kNoResourcesErr );
1555         require_noerr( err, exit );
1556
1557         // Register to listen for address list changes.
1558         
1559         gInterfaceListChangedEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
1560         err = translate_errno( gInterfaceListChangedEvent, (mStatus) GetLastError(), kUnknownErr );
1561         require_noerr( err, exit );
1562
1563         sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
1564         err = translate_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
1565         require_noerr( err, exit );
1566         gInterfaceListChangedSocket = sock;
1567         
1568         // Make the socket non-blocking so the WSAIoctl returns immediately with WSAEWOULDBLOCK. It will set the event 
1569         // when a change to the interface list is detected.
1570         
1571         param = 1;
1572         err = ioctlsocket( sock, FIONBIO, &param );
1573         err = translate_errno( err == 0, errno_compat(), kUnknownErr );
1574         require_noerr( err, exit );
1575         
1576         inBuffer        = 0;
1577         outBuffer       = 0;
1578         err = WSAIoctl( sock, SIO_ADDRESS_LIST_CHANGE, &inBuffer, 0, &outBuffer, 0, &outSize, NULL, NULL );
1579         if( err < 0 )
1580         {
1581                 check( errno_compat() == WSAEWOULDBLOCK );
1582         }
1583         
1584         err = WSAEventSelect( sock, gInterfaceListChangedEvent, FD_ADDRESS_LIST_CHANGE );
1585         err = translate_errno( err == 0, errno_compat(), kUnknownErr );
1586         require_noerr( err, exit );
1587
1588         gDescChangedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
1589         err = translate_errno( gDescChangedEvent, (mStatus) GetLastError(), kUnknownErr );
1590         require_noerr( err, exit );
1591
1592         if ( gDescKey != NULL )
1593         {
1594                 err = RegNotifyChangeKeyValue( gDescKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET, gDescChangedEvent, TRUE);
1595                 require_noerr( err, exit );
1596         }
1597
1598         // This will catch all changes to tcp/ip networking, including changes to the domain search list
1599
1600         gTcpipChangedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
1601         err = translate_errno( gTcpipChangedEvent, (mStatus) GetLastError(), kUnknownErr );
1602         require_noerr( err, exit );
1603
1604         err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), &gTcpipKey );
1605         require_noerr( err, exit );
1606
1607         err = RegNotifyChangeKeyValue( gTcpipKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gTcpipChangedEvent, TRUE);
1608         require_noerr( err, exit );
1609
1610         // This will catch all changes to ddns configuration
1611
1612         gDdnsChangedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
1613         err = translate_errno( gDdnsChangedEvent, (mStatus) GetLastError(), kUnknownErr );
1614         require_noerr( err, exit );
1615
1616         err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode TEXT("\\DynDNS\\Setup"), &gDdnsKey );
1617         require_noerr( err, exit );
1618
1619         err = RegNotifyChangeKeyValue( gDdnsKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gDdnsChangedEvent, TRUE);
1620         require_noerr( err, exit );
1621
1622         // This will catch all changes to file sharing
1623
1624         gFileSharingChangedEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
1625         err = translate_errno( gFileSharingChangedEvent, (mStatus) GetLastError(), kUnknownErr );
1626         require_noerr( err, exit );
1627
1628         err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\Shares"), &gFileSharingKey );
1629         require_noerr( err, exit );
1630
1631         err = RegNotifyChangeKeyValue( gFileSharingKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gFileSharingChangedEvent, TRUE);
1632         require_noerr( err, exit );
1633
1634         // This will catch changes to the Windows firewall
1635
1636         gFirewallChangedEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
1637         err = translate_errno( gFirewallChangedEvent, (mStatus) GetLastError(), kUnknownErr );
1638         require_noerr( err, exit );
1639
1640         // Just to make sure that initialization doesn't fail on some old OS
1641         // that doesn't have this key, we'll only add the notification if
1642         // the key exists.
1643
1644         err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\SharedAccess\\Parameters\\FirewallPolicy\\FirewallRules"), &gFirewallKey );
1645         
1646         if ( !err )
1647         {
1648                 err = RegNotifyChangeKeyValue( gFirewallKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gFirewallChangedEvent, TRUE);
1649                 require_noerr( err, exit );
1650         }
1651         else
1652         {
1653                 err = mStatus_NoError;
1654         }
1655
1656         gSPSWakeupEvent = CreateWaitableTimer( NULL, FALSE, NULL );
1657         err = translate_errno( gSPSWakeupEvent, (mStatus) GetLastError(), kUnknownErr );
1658         require_noerr( err, exit );
1659
1660         gSPSSleepEvent = CreateWaitableTimer( NULL, FALSE, NULL );
1661         err = translate_errno( gSPSSleepEvent, (mStatus) GetLastError(), kUnknownErr );
1662         require_noerr( err, exit );
1663
1664         gUDSEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
1665         err = translate_errno( gUDSEvent, ( mStatus ) GetLastError(), kUnknownErr );
1666         require_noerr( err, exit );
1667
1668 exit:
1669         if( err )
1670         {
1671                 TearDownNotifications();
1672         }
1673         return( err );
1674 }
1675
1676 //===========================================================================================================================
1677 //      TearDownNotifications
1678 //===========================================================================================================================
1679
1680 mDNSlocal mStatus       TearDownNotifications()
1681 {
1682         if ( gStopEvent )
1683         {
1684                 CloseHandle( gStopEvent );
1685                 gStopEvent = NULL;
1686         }
1687
1688         if( IsValidSocket( gInterfaceListChangedSocket ) )
1689         {
1690                 close_compat( gInterfaceListChangedSocket );
1691                 gInterfaceListChangedSocket = kInvalidSocketRef;
1692         }
1693
1694         if( gInterfaceListChangedEvent )
1695         {
1696                 CloseHandle( gInterfaceListChangedEvent );
1697                 gInterfaceListChangedEvent = 0;
1698         }
1699
1700         if ( gDescChangedEvent != NULL )
1701         {
1702                 CloseHandle( gDescChangedEvent );
1703                 gDescChangedEvent = NULL;
1704         }
1705
1706         if ( gDescKey != NULL )
1707         {
1708                 RegCloseKey( gDescKey );
1709                 gDescKey = NULL;
1710         }
1711
1712         if ( gTcpipChangedEvent != NULL )
1713         {
1714                 CloseHandle( gTcpipChangedEvent );
1715                 gTcpipChangedEvent = NULL;
1716         }
1717
1718         if ( gDdnsChangedEvent != NULL )
1719         {
1720                 CloseHandle( gDdnsChangedEvent );
1721                 gDdnsChangedEvent = NULL;
1722         }
1723
1724         if ( gDdnsKey != NULL )
1725         {
1726                 RegCloseKey( gDdnsKey );
1727                 gDdnsKey = NULL;
1728         }
1729
1730         if ( gFileSharingChangedEvent != NULL )
1731         {
1732                 CloseHandle( gFileSharingChangedEvent );
1733                 gFileSharingChangedEvent = NULL;
1734         }
1735
1736         if ( gFileSharingKey != NULL )
1737         {
1738                 RegCloseKey( gFileSharingKey );
1739                 gFileSharingKey = NULL;
1740         }
1741
1742         if ( gFirewallChangedEvent != NULL )
1743         {
1744                 CloseHandle( gFirewallChangedEvent );
1745                 gFirewallChangedEvent = NULL;
1746         }
1747
1748         if ( gFirewallKey != NULL )
1749         {
1750                 RegCloseKey( gFirewallKey );
1751                 gFirewallKey = NULL;
1752         }
1753
1754         if ( gSPSWakeupEvent )
1755         {
1756                 CloseHandle( gSPSWakeupEvent );
1757                 gSPSWakeupEvent = NULL;
1758         }
1759
1760         if ( gSPSSleepEvent )
1761         {
1762                 CloseHandle( gSPSSleepEvent );
1763                 gSPSSleepEvent = NULL;
1764         }
1765
1766         return( mStatus_NoError );
1767 }
1768
1769
1770 //===========================================================================================================================
1771 //      RegisterWaitableEvent
1772 //===========================================================================================================================
1773
1774 static mStatus RegisterWaitableEvent( mDNS * const inMDNS, HANDLE event, void * context, RegisterWaitableEventHandler handler )
1775 {
1776         EventSource * source;
1777         mStatus err = mStatus_NoError;
1778
1779         ( void ) inMDNS;
1780         check( event );
1781         check( handler );
1782
1783         source = ( EventSource* ) malloc( sizeof( EventSource ) );
1784         require_action( source, exit, err = mStatus_NoMemoryErr );
1785         mDNSPlatformMemZero( source, sizeof( EventSource ) );
1786         source->event = event;
1787         source->context = context;
1788         source->handler = handler;
1789
1790         source->next                    = gEventSourceList;
1791         gEventSourceList                = source;
1792         gEventSourceListChanged = TRUE;
1793         gEventSources++;
1794
1795 exit:
1796
1797         return err;
1798 }
1799
1800
1801 //===========================================================================================================================
1802 //      UnregisterWaitableEvent
1803 //===========================================================================================================================
1804
1805 static void UnregisterWaitableEvent( mDNS * const inMDNS, HANDLE event )
1806 {
1807         EventSource     *       current = gEventSourceList;
1808         EventSource     *       last    = NULL;
1809
1810         ( void ) inMDNS;
1811         check( event );
1812
1813         while ( current )
1814         {
1815                 if ( current->event == event )
1816                 {
1817                         if ( last == NULL )
1818                         {
1819                                 gEventSourceList = current->next;
1820                         }
1821                         else
1822                         {
1823                                 last->next = current->next;
1824                         }
1825
1826                         gEventSourceListChanged = TRUE;
1827                         gEventSources--;
1828                         free( current );
1829
1830                         break;
1831                 }
1832
1833                 last    = current;
1834                 current = current->next;
1835         }
1836 }
1837
1838
1839 //===========================================================================================================================
1840 //      SetupWaitList
1841 //===========================================================================================================================
1842
1843 mDNSlocal mStatus SetupWaitList( mDNS * const inMDNS, HANDLE **outWaitList, int *outWaitListCount )
1844 {
1845         int                             waitListCount;
1846         HANDLE          *       waitList;
1847         HANDLE          *       waitItemPtr;
1848         EventSource     *       source;
1849         mStatus                 err;
1850         
1851         dlog( kDebugLevelTrace, DEBUG_NAME "setting up wait list\n" );
1852         
1853         ( void ) inMDNS;
1854         check( inMDNS->p );
1855         check( outWaitList );
1856         check( outWaitListCount );
1857         
1858         // Allocate an array to hold all the objects to wait on.
1859         
1860         waitListCount = kWaitListFixedItemCount + gEventSources;
1861         waitList = ( HANDLE* ) malloc( waitListCount * sizeof( *waitList ) );
1862         require_action( waitList, exit, err = mStatus_NoMemoryErr );
1863         waitItemPtr = waitList;
1864         
1865         // Add the fixed wait items to the beginning of the list.
1866         
1867         *waitItemPtr++  =       gStopEvent;
1868         *waitItemPtr++  =       gInterfaceListChangedEvent;
1869         *waitItemPtr++  =       gDescChangedEvent;
1870         *waitItemPtr++  =       gTcpipChangedEvent;
1871         *waitItemPtr++  =       gDdnsChangedEvent;
1872         *waitItemPtr++  =       gFileSharingChangedEvent;
1873         *waitItemPtr++  =       gFirewallChangedEvent;
1874         *waitItemPtr++  =       gSPSWakeupEvent;
1875         *waitItemPtr++  =       gSPSSleepEvent;
1876
1877         for ( source = gEventSourceList; source; source = source->next )
1878         {
1879                 *waitItemPtr++ = source->event;
1880         }
1881
1882         check( ( int )( waitItemPtr - waitList ) == waitListCount );
1883         
1884         *outWaitList            = waitList;
1885         *outWaitListCount       = waitListCount;
1886         waitList                        = NULL;
1887         err                                     = mStatus_NoError;
1888         
1889 exit:
1890
1891         if( waitList )
1892         {
1893                 free( waitList );
1894         }
1895
1896         dlog( kDebugLevelTrace, DEBUG_NAME "setting up wait list done (err=%d %m)\n", err, err );
1897         return( err );
1898 }
1899
1900
1901 //===========================================================================================================================
1902 //      CoreCallback
1903 //===========================================================================================================================
1904
1905 static void
1906 CoreCallback(mDNS * const inMDNS, mStatus status)
1907 {
1908         if (status == mStatus_ConfigChanged)
1909         {
1910                 SetLLRoute( inMDNS );
1911         }
1912 }
1913
1914
1915 //===========================================================================================================================
1916 //      UDSCanAccept
1917 //===========================================================================================================================
1918
1919 mDNSlocal void UDSCanAccept( mDNS * const inMDNS, HANDLE event, void * context )
1920 {
1921         ( void ) inMDNS;
1922         ( void ) event;
1923         
1924         if ( gUDSCallback )
1925         {
1926                 gUDSCallback( ( int ) gUDSSocket, 0, context );
1927         }
1928 }
1929
1930
1931 //===========================================================================================================================
1932 //      UDSCanRead
1933 //===========================================================================================================================
1934
1935 mDNSlocal void UDSCanRead( TCPSocket * sock )
1936 {
1937         udsEventCallback callback = ( udsEventCallback ) sock->userCallback;
1938
1939         if ( callback )
1940         {
1941                 callback( (int) sock->fd, 0, sock->userContext );
1942         }
1943 }
1944
1945
1946 //===========================================================================================================================
1947 //      udsSupportAddFDToEventLoop
1948 //===========================================================================================================================
1949
1950 mStatus
1951 udsSupportAddFDToEventLoop( SocketRef fd, udsEventCallback callback, void *context, void **platform_data)
1952 {
1953         mStatus err = mStatus_NoError;
1954
1955         // We are using some knowledge of what is being passed to us here.  If the fd is a listen socket,
1956         // then the "callback" parameter is NULL.  If it is an actual read/write socket, then the "callback"
1957         // parameter is not null. This is important because we use waitable events for the listen socket
1958         // and alertable I/O for the read/write sockets.
1959
1960         if ( context )
1961         {
1962                 TCPSocket * sock;
1963
1964                 sock = malloc( sizeof( TCPSocket ) );
1965                 require_action( sock, exit, err = mStatus_NoMemoryErr );
1966                 mDNSPlatformMemZero( sock, sizeof( TCPSocket ) );
1967
1968                 sock->fd                                = (SOCKET) fd;
1969                 sock->readEventHandler  = UDSCanRead;
1970                 sock->userCallback              = callback;
1971                 sock->userContext               = context;
1972                 sock->m                                 = &gMDNSRecord;
1973
1974                 err = TCPAddSocket( sock->m, sock );
1975                 require_noerr( err, exit );
1976
1977                 *platform_data = sock;
1978         }
1979         else
1980         {
1981                 gUDSSocket              = fd;
1982                 gUDSCallback    = callback;
1983                 gUDSEvent               = CreateEvent( NULL, FALSE, FALSE, NULL );
1984                 err = translate_errno( gUDSEvent, (mStatus) GetLastError(), kUnknownErr );
1985                 require_noerr( err, exit ); 
1986                 err = WSAEventSelect( fd, gUDSEvent, FD_ACCEPT | FD_CLOSE );\r
1987                 err = translate_errno( err == 0, WSAGetLastError(), kNoResourcesErr );\r
1988                 require_noerr( err, exit );
1989                 err = RegisterWaitableEvent( &gMDNSRecord, gUDSEvent, context, UDSCanAccept );
1990                 require_noerr( err, exit );
1991         }
1992
1993 exit:
1994
1995         return err;
1996 }
1997
1998
1999 int
2000 udsSupportReadFD( SocketRef fd, char *buf, int len, int flags, void *platform_data )
2001 {
2002         TCPSocket       *       sock;
2003         mDNSBool                closed;
2004         int                             ret;
2005
2006         ( void ) flags;
2007
2008         sock = ( TCPSocket* ) platform_data;
2009         require_action( sock, exit, ret = -1 );
2010         require_action( sock->fd == fd, exit, ret = -1 );
2011
2012         ret = mDNSPlatformReadTCP( sock, buf, len, &closed );
2013
2014         if ( closed )
2015         {
2016                 ret = 0;
2017         }
2018
2019 exit:
2020
2021         return ret;
2022 }
2023
2024
2025 mStatus
2026 udsSupportRemoveFDFromEventLoop( SocketRef fd, void *platform_data)             // Note: This also CLOSES the socket
2027 {
2028         mStatus err = kNoErr;
2029
2030         if ( platform_data != NULL )
2031         {
2032                 TCPSocket * sock;
2033
2034                 dlog( kDebugLevelInfo, DEBUG_NAME "session closed\n" );
2035                 sock = ( TCPSocket* ) platform_data;
2036                 check( sock->fd == fd );
2037                 mDNSPlatformTCPCloseConnection( sock );
2038         }
2039         else if ( gUDSEvent != NULL )
2040         {
2041                 UnregisterWaitableEvent( &gMDNSRecord, gUDSEvent );
2042                 WSAEventSelect( fd, gUDSEvent, 0 );
2043                 CloseHandle( gUDSEvent );
2044                 gUDSEvent = NULL;
2045         }
2046
2047         return err;
2048 }
2049
2050
2051 mDNSexport void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay)
2052         {
2053         (void)m;
2054         (void)delay;
2055         // No-op, for now
2056         }
2057
2058
2059 //===========================================================================================================================
2060 //      SystemWakeForNetworkAccess
2061 //===========================================================================================================================
2062
2063 mDNSu8
2064 SystemWakeForNetworkAccess( LARGE_INTEGER * timeout )
2065 {
2066         HKEY                                    key = NULL;
2067         DWORD                                   dwSize;
2068         DWORD                                   enabled;
2069         mDNSu8                                  ok;
2070         SYSTEM_POWER_STATUS             powerStatus;
2071         time_t                                  startTime;
2072         time_t                                  nextWakeupTime;
2073         time_t                                  delta;
2074         __int64                                 delta64;
2075         DWORD                                   err;
2076
2077         dlog( kDebugLevelInfo, DEBUG_NAME "SystemWakeForNetworkAccess\n" );
2078
2079         // Make sure we have a timer
2080
2081         require_action( gSPSWakeupEvent != NULL, exit, ok = FALSE );
2082         require_action( gSPSSleepEvent != NULL, exit, ok = FALSE );
2083
2084         // Make sure the user enabled bonjour sleep proxy client 
2085         
2086         err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Power Management", &key );
2087         require_action( !err, exit, ok = FALSE );
2088         dwSize = sizeof( DWORD );
2089         err = RegQueryValueEx( key, L"Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize );
2090         require_action( !err, exit, ok = FALSE );
2091         require_action( enabled, exit, ok = FALSE );
2092         
2093         // Make sure machine is on AC power
2094         
2095         ok = ( mDNSu8 ) GetSystemPowerStatus( &powerStatus );
2096         require_action( ok, exit, ok = FALSE );
2097         require_action( powerStatus.ACLineStatus == AC_LINE_ONLINE, exit, ok = FALSE );
2098
2099         // Now make sure we have a network interface that does wake-on-lan
2100
2101         ok = ( mDNSu8 ) IsWOMPEnabled( &gMDNSRecord );
2102         require_action( ok, exit, ok = FALSE );
2103
2104         // Calculate next wake up time
2105
2106         startTime               = time( NULL );                                 // Seconds since midnight January 1, 1970
2107         nextWakeupTime  = startTime + ( 120 * 60 );             // 2 hours later
2108         
2109         if ( gMDNSRecord.p->nextDHCPLeaseExpires < nextWakeupTime )
2110         {
2111                 nextWakeupTime = gMDNSRecord.p->nextDHCPLeaseExpires;
2112         }
2113
2114         // Finally calculate the next relative wakeup time
2115
2116         delta = ( time_t ) ( ( ( double )( nextWakeupTime - startTime ) ) * 0.9 );
2117         delta64 = -delta * 10000000;
2118         timeout->LowPart  = (DWORD) ( delta64 & 0xFFFFFFFF );
2119         timeout->HighPart = (LONG)  ( delta64 >> 32 );
2120
2121         dlog( kDebugLevelInfo, DEBUG_NAME "enabling sleep proxy client with next wakeup time %d seconds from now\n", delta );
2122
2123         ok = TRUE;
2124
2125 exit:
2126
2127         if ( key )
2128         {
2129                 RegCloseKey( key );
2130         }
2131
2132         return ok;
2133 }
2134
2135
2136 //===========================================================================================================================
2137 //      HaveRoute
2138 //===========================================================================================================================
2139
2140 static bool
2141 HaveRoute( PMIB_IPFORWARDROW rowExtant, unsigned long addr, unsigned long metric )
2142 {
2143         PMIB_IPFORWARDTABLE     pIpForwardTable = NULL;
2144         DWORD                           dwSize                  = 0;
2145         BOOL                            bOrder                  = FALSE;
2146         OSStatus                        err;
2147         bool                            found                   = false;
2148         unsigned long int       i;
2149
2150         //
2151         // Find out how big our buffer needs to be.
2152         //
2153         err = GetIpForwardTable(NULL, &dwSize, bOrder);
2154         require_action( err == ERROR_INSUFFICIENT_BUFFER, exit, err = kUnknownErr );
2155
2156         //
2157         // Allocate the memory for the table
2158         //
2159         pIpForwardTable = (PMIB_IPFORWARDTABLE) malloc( dwSize );
2160         require_action( pIpForwardTable, exit, err = kNoMemoryErr );
2161   
2162         //
2163         // Now get the table.
2164         //
2165         err = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder);
2166         require_noerr( err, exit );
2167
2168         //
2169         // Search for the row in the table we want.
2170         //
2171         for ( i = 0; i < pIpForwardTable->dwNumEntries; i++)
2172         {
2173                 if ( ( pIpForwardTable->table[i].dwForwardDest == addr ) && ( !metric || ( pIpForwardTable->table[i].dwForwardMetric1 == metric ) ) )
2174                 {
2175                         memcpy( rowExtant, &(pIpForwardTable->table[i]), sizeof(*rowExtant) );
2176                         found = true;
2177                         break;
2178                 }
2179         }
2180
2181 exit:
2182
2183         if ( pIpForwardTable != NULL ) 
2184         {
2185                 free(pIpForwardTable);
2186         }
2187     
2188         return found;
2189 }
2190
2191
2192 //===========================================================================================================================
2193 //      IsValidAddress
2194 //===========================================================================================================================
2195
2196 static bool
2197 IsValidAddress( const char * addr )
2198 {
2199         return ( addr && ( strcmp( addr, "0.0.0.0" ) != 0 ) ) ? true : false;
2200 }       
2201
2202
2203 //===========================================================================================================================
2204 //      GetAdditionalMetric
2205 //===========================================================================================================================
2206
2207 static ULONG
2208 GetAdditionalMetric( DWORD ifIndex )
2209 {
2210         ULONG metric = 0;
2211
2212         if( !gIPHelperLibraryInstance )
2213         {
2214                 gIPHelperLibraryInstance = LoadLibrary( TEXT( "Iphlpapi" ) );
2215
2216                 gGetIpInterfaceEntryFunctionPtr = 
2217                                 (GetIpInterfaceEntryFunctionPtr) GetProcAddress( gIPHelperLibraryInstance, "GetIpInterfaceEntry" );
2218
2219                 if( !gGetIpInterfaceEntryFunctionPtr )
2220                 {               
2221                         BOOL ok;
2222                                 
2223                         ok = FreeLibrary( gIPHelperLibraryInstance );
2224                         check_translated_errno( ok, GetLastError(), kUnknownErr );
2225                         gIPHelperLibraryInstance = NULL;
2226                 }
2227         }
2228
2229         if ( gGetIpInterfaceEntryFunctionPtr )
2230         {
2231                 MIB_IPINTERFACE_ROW row;
2232                 DWORD err;
2233
2234                 ZeroMemory( &row, sizeof( MIB_IPINTERFACE_ROW ) );
2235                 row.Family = AF_INET;
2236                 row.InterfaceIndex = ifIndex;
2237                 err = gGetIpInterfaceEntryFunctionPtr( &row );
2238                 require_noerr( err, exit );
2239                 metric = row.Metric + 256;
2240         }
2241
2242 exit:
2243
2244         return metric;
2245 }
2246
2247
2248 //===========================================================================================================================
2249 //      SetLLRoute
2250 //===========================================================================================================================
2251
2252 static OSStatus
2253 SetLLRoute( mDNS * const inMDNS )
2254 {
2255         OSStatus err = kNoErr;
2256
2257         DEBUG_UNUSED( inMDNS );
2258
2259         //
2260         // <rdar://problem/4096464> Don't call SetLLRoute on loopback
2261         // <rdar://problem/6885843> Default route on Windows 7 breaks network connectivity
2262         // 
2263         // Don't mess w/ the routing table on Vista and later OSes, as 
2264         // they have a permanent route to link-local addresses. Otherwise,
2265         // set a route to link local addresses (169.254.0.0)
2266         //
2267         if ( ( gOSMajorVersion < 6 ) && gServiceManageLLRouting && !gPlatformStorage.registeredLoopback4 )
2268         {
2269                 DWORD                           ifIndex;
2270                 MIB_IPFORWARDROW        rowExtant;
2271                 bool                            addRoute;
2272                 MIB_IPFORWARDROW        row;
2273
2274                 ZeroMemory(&row, sizeof(row));
2275
2276                 err = GetRouteDestination(&ifIndex, &row.dwForwardNextHop);
2277                 require_noerr( err, exit );
2278                 row.dwForwardDest               = inet_addr(kLLNetworkAddr);
2279                 row.dwForwardIfIndex    = ifIndex;
2280                 row.dwForwardMask               = inet_addr(kLLNetworkAddrMask);
2281                 row.dwForwardType               = 3;
2282                 row.dwForwardProto              = MIB_IPPROTO_NETMGMT;
2283                 row.dwForwardAge                = 0;
2284                 row.dwForwardPolicy             = 0;
2285                 row.dwForwardMetric1    = 20 + GetAdditionalMetric( ifIndex );
2286                 row.dwForwardMetric2    = (DWORD) - 1;
2287                 row.dwForwardMetric3    = (DWORD) - 1;
2288                 row.dwForwardMetric4    = (DWORD) - 1;
2289                 row.dwForwardMetric5    = (DWORD) - 1;
2290
2291                 addRoute = true;
2292
2293                 //
2294                 // check to make sure we don't already have a route
2295                 //
2296                 if ( HaveRoute( &rowExtant, inet_addr( kLLNetworkAddr ), 0 ) )
2297                 {
2298                         //
2299                         // set the age to 0 so that we can do a memcmp.
2300                         //
2301                         rowExtant.dwForwardAge = 0;
2302
2303                         //
2304                         // check to see if this route is the same as our route
2305                         //
2306                         if (memcmp(&row, &rowExtant, sizeof(row)) != 0)
2307                         {
2308                                 //
2309                                 // if it isn't then delete this entry
2310                                 //
2311                                 DeleteIpForwardEntry(&rowExtant);
2312                         }
2313                         else
2314                         {
2315                                 //
2316                                 // else it is, so we don't want to create another route
2317                                 //
2318                                 addRoute = false;
2319                         }
2320                 }
2321
2322                 if (addRoute && row.dwForwardNextHop)
2323                 {
2324                         err = CreateIpForwardEntry(&row);
2325                         check_noerr( err );
2326                 }
2327         }
2328
2329 exit:
2330
2331         return ( err );
2332 }
2333
2334
2335 //===========================================================================================================================
2336 //      GetRouteDestination
2337 //===========================================================================================================================
2338
2339 static OSStatus
2340 GetRouteDestination(DWORD * ifIndex, DWORD * address)
2341 {
2342         struct in_addr          ia;
2343         IP_ADAPTER_INFO *       pAdapterInfo    =       NULL;
2344         IP_ADAPTER_INFO *       pAdapter                =       NULL;
2345         ULONG                           bufLen;
2346         mDNSBool                        done                    =       mDNSfalse;
2347         OSStatus                        err;
2348
2349         //
2350         // GetBestInterface will fail if there is no default gateway
2351         // configured.  If that happens, we will just take the first
2352         // interface in the list. MSDN support says there is no surefire
2353         // way to manually determine what the best interface might
2354         // be for a particular network address.
2355         //
2356         ia.s_addr       =       inet_addr(kLLNetworkAddr);
2357         err                     =       GetBestInterface(*(IPAddr*) &ia, ifIndex);
2358
2359         if (err)
2360         {
2361                 *ifIndex = 0;
2362         }
2363
2364         //
2365         // Make an initial call to GetAdaptersInfo to get
2366         // the necessary size into the bufLen variable
2367         //
2368         err = GetAdaptersInfo( NULL, &bufLen);
2369         require_action( err == ERROR_BUFFER_OVERFLOW, exit, err = kUnknownErr );
2370
2371         pAdapterInfo = (IP_ADAPTER_INFO*) malloc( bufLen );
2372         require_action( pAdapterInfo, exit, err = kNoMemoryErr );
2373         
2374         err = GetAdaptersInfo( pAdapterInfo, &bufLen);
2375         require_noerr( err, exit );
2376         
2377         pAdapter        =       pAdapterInfo;
2378         err                     =       kUnknownErr;
2379                         
2380         // <rdar://problem/3718122>
2381         // <rdar://problem/5652098>
2382         //
2383         // Look for the Nortel VPN virtual interface, along with Juniper virtual interface.
2384         //
2385         // If these interfaces are active (i.e., has a non-zero IP Address),
2386         // then we want to disable routing table modifications.
2387
2388         while (pAdapter)
2389         {
2390                 if ( ( IsNortelVPN( pAdapter ) || IsJuniperVPN( pAdapter ) || IsCiscoVPN( pAdapter ) ) &&
2391                          ( inet_addr( pAdapter->IpAddressList.IpAddress.String ) != 0 ) )
2392                 {
2393                         dlog( kDebugLevelTrace, DEBUG_NAME "disabling routing table management due to VPN incompatibility" );
2394                         goto exit;
2395                 }
2396
2397                 pAdapter = pAdapter->Next;
2398         }
2399
2400         while ( !done )
2401         {
2402                 pAdapter        =       pAdapterInfo;
2403                 err                     =       kUnknownErr;
2404
2405                 while (pAdapter)
2406                 {
2407                         // If we don't have an interface selected, choose the first one that is of type ethernet and
2408                         // has a valid IP Address
2409
2410                         if ((pAdapter->Type == MIB_IF_TYPE_ETHERNET) && ( IsValidAddress( pAdapter->IpAddressList.IpAddress.String ) ) && (!(*ifIndex) || (pAdapter->Index == (*ifIndex))))
2411                         {
2412                                 *address =      inet_addr( pAdapter->IpAddressList.IpAddress.String );
2413                                 *ifIndex =  pAdapter->Index;
2414                                 err              =      kNoErr;
2415                                 break;
2416                         }
2417                 
2418                         pAdapter = pAdapter->Next;
2419                 }
2420
2421                 // If we found the right interface, or we weren't trying to find a specific interface then we're done
2422
2423                 if ( !err || !( *ifIndex) )
2424                 {
2425                         done = mDNStrue;
2426                 }
2427
2428                 // Otherwise, try again by wildcarding the interface
2429
2430                 else
2431                 {
2432                         *ifIndex = 0;
2433                 }
2434         } 
2435
2436 exit:
2437
2438         if ( pAdapterInfo != NULL )
2439         {
2440                 free( pAdapterInfo );
2441         }
2442
2443         return( err );
2444 }
2445
2446
2447 static bool
2448 IsNortelVPN( IP_ADAPTER_INFO * pAdapter )
2449 {
2450         return ((pAdapter->Type == MIB_IF_TYPE_ETHERNET) &&
2451                     (pAdapter->AddressLength == 6) &&
2452                     (pAdapter->Address[0] == 0x44) &&
2453                     (pAdapter->Address[1] == 0x45) &&
2454                     (pAdapter->Address[2] == 0x53) &&
2455                     (pAdapter->Address[3] == 0x54) &&
2456                     (pAdapter->Address[4] == 0x42) &&
2457                         (pAdapter->Address[5] == 0x00)) ? true : false;
2458 }
2459
2460
2461 static bool
2462 IsJuniperVPN( IP_ADAPTER_INFO * pAdapter )
2463 {       
2464         return ( strnistr( pAdapter->Description, "Juniper", sizeof( pAdapter->Description  ) ) != NULL ) ? true : false;
2465 }
2466
2467
2468 static bool
2469 IsCiscoVPN( IP_ADAPTER_INFO * pAdapter )
2470 {
2471         return ((pAdapter->Type == MIB_IF_TYPE_ETHERNET) &&
2472                     (pAdapter->AddressLength == 6) &&
2473                     (pAdapter->Address[0] == 0x00) &&
2474                     (pAdapter->Address[1] == 0x05) &&
2475                     (pAdapter->Address[2] == 0x9a) &&
2476                     (pAdapter->Address[3] == 0x3c) &&
2477                     (pAdapter->Address[4] == 0x7a) &&
2478                         (pAdapter->Address[5] == 0x00)) ? true : false;
2479 }
2480
2481
2482 static const char *
2483 strnistr( const char * string, const char * subString, size_t max )
2484 {
2485         size_t       subStringLen;
2486         size_t       offset;
2487         size_t       maxOffset;
2488         size_t       stringLen;
2489         const char * pPos;
2490
2491         if ( ( string == NULL ) || ( subString == NULL ) )
2492         {
2493                 return string;
2494         }
2495
2496         stringLen = ( max > strlen( string ) ) ? strlen( string ) : max;
2497
2498         if ( stringLen == 0 )
2499         {
2500                 return NULL;
2501         }
2502         
2503         subStringLen = strlen( subString );
2504
2505         if ( subStringLen == 0 )
2506         {
2507                 return string;
2508         }
2509
2510         if ( subStringLen > stringLen )
2511         {
2512                 return NULL;
2513         }
2514
2515         maxOffset = stringLen - subStringLen;
2516         pPos      = string;
2517
2518         for ( offset = 0; offset <= maxOffset; offset++ )
2519         {
2520                 if ( _strnicmp( pPos, subString, subStringLen ) == 0 )
2521                 {
2522                         return pPos;
2523                 }
2524
2525                 pPos++;
2526         }
2527
2528         return NULL;
2529 }
2530