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