/* * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * The contents of this file constitute Original Code as defined in and * are subject to the Apple Public Source License Version 1.1 (the * "License"). You may not use this file except in compliance with the * License. Please obtain a copy of the License at * http://www.apple.com/publicsource and read it before using this file. * * This Original Code and all software distributed under the License are * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License. * * @APPLE_LICENSE_HEADER_END@ */ /*! * @header ServerControl */ #if DEBUG_SRVR # include // for stderr, fprintf(), et al #endif #include "ServerControl.h" #include "CHandlers.h" #include "CListener.h" #include "DSTCPListener.h" #include "CMsgQueue.h" #include "CRefTable.h" #include "DSMutexSemaphore.h" #include "DSCThread.h" #include "CServerPlugin.h" #include "CPluginHandler.h" #include "CNodeList.h" #include "CLog.h" #include #include #include #include //used for mkdir and stat #include #include //required for power management handling #include // for syslog() #include // for time //power management extern void dsPMNotificationHandler ( void *refContext, io_service_t service, natural_t messageType, void *notificationID ); extern io_object_t gPMDeregisterNotifier; extern io_connect_t gPMKernelPort; //network change extern boolean_t NetworkChangeCallBack(SCDynamicStoreRef aSCDStore, void *callback_argument); extern CFRunLoopRef gServerRunLoop; extern time_t gSunsetTime; extern dsBool gLogAPICalls; // --------------------------------------------------------------------------- // * Globals // // --------------------------------------------------------------------------- ServerControl *gSrvrCntl = nil; CRefTable *gRefTable = nil; CPlugInList *gPlugins = nil; CMsgQueue *gTCPMsgQueue = nil; CMsgQueue *gMsgQueue = nil; CMsgQueue *gInternalMsgQueue = nil; CMsgQueue *gCheckpwMsgQueue = nil; CNodeList *gNodeList = nil; name_t gServerName = "DirectoryService"; //KW use constant string here DSMutexSemaphore *gTCPHandlerLock = new DSMutexSemaphore(); //mutex on create and destroy of CHandler threads DSMutexSemaphore *gHandlerLock = new DSMutexSemaphore(); //mutex on create and destroy of CHandler threads DSMutexSemaphore *gInternalHandlerLock = new DSMutexSemaphore(); //mutex on create and destroy of CHandler Internal threads DSMutexSemaphore *gCheckpwHandlerLock = new DSMutexSemaphore(); //mutex on create and destroy of CHandler Checkpw threads uInt32 gDaemonPID; uInt32 gDaemonIPAddress; static mach_port_t gClient_Death_Notify_Port = NULL; void ClientDeathCallback(CFMachPortRef port, void *voidmsg, CFIndex size, void *info); void ClientDeathCallback(CFMachPortRef port, void *voidmsg, CFIndex size, void *info) { mach_msg_header_t *msg = (mach_msg_header_t *)voidmsg; if (msg->msgh_id == MACH_NOTIFY_DEAD_NAME) { const mach_dead_name_notification_t *const deathMessage = (mach_dead_name_notification_t *)msg; DBGLOG1( kLogApplication, "Client that used port %d has died or port has been deallocated.", deathMessage->not_port ); // Deallocate the send right that came in the dead name notification mach_port_destroy( mach_task_self(), deathMessage->not_port ); } }// ClientDeathCallback //when we receive the message first time we do this void EnableDeathNotificationForClient(mach_port_t port); void EnableDeathNotificationForClient(mach_port_t port) { mach_port_t prev; if (gClient_Death_Notify_Port != NULL) { kern_return_t r = mach_port_request_notification( mach_task_self(), port, MACH_NOTIFY_DEAD_NAME, 0, gClient_Death_Notify_Port, MACH_MSG_TYPE_MAKE_SEND_ONCE, &prev); // If the port already died while we thought to register for its death, then log this if (r != KERN_SUCCESS) { DBGLOG1( kLogApplication, "Can't register for dead port notification since port %d already gone.", port ); } } } // EnableDeathNotificationForClient void DoPeriodicTask(CFRunLoopTimerRef timer, void *info); CFStringRef PeriodicTaskCopyStringCallback( const void *item ); CFStringRef PeriodicTaskCopyStringCallback( const void *item ) { return CFSTR("PeriodicTask"); } // --------------------------------------------------------------------------- // * ServerControl() // // --------------------------------------------------------------------------- ServerControl::ServerControl ( void ) { uInt32 i = 0; gDaemonPID = getpid(); //we use a non valid IP Address of zero for ourselves gDaemonIPAddress = 0; fListener = nil; fTCPListener = nil; fTCPHandlerThreadsCnt = 0; fHandlerThreadsCnt = 0; fInternalHandlerThreadsCnt = 0; fCheckpwHandlerThreadsCnt = 0; fSCDStore = 0; for ( i = 0; i < kMaxHandlerThreads; i++) { fTCPHandlers[ i ] = nil; } for ( i = 0; i < kMaxHandlerThreads; i++) { fHandlers[ i ] = nil; } for ( i = 0; i < kMaxInternalHandlerThreads; i++) { fInternalHandlers[ i ] = nil; } for ( i = 0; i < kMaxCheckpwHandlerThreads; i++) { fCheckpwHandlers[ i ] = nil; } fTCPHandlerSemaphore = new DSSemaphore( fTCPHandlerThreadsCnt ); fHandlerSemaphore = new DSSemaphore( fHandlerThreadsCnt ); fInternalHandlerSemaphore = new DSSemaphore( fInternalHandlerThreadsCnt ); fCheckpwHandlerSemaphore = new DSSemaphore( fCheckpwHandlerThreadsCnt ); } // ServerControl // --------------------------------------------------------------------------- // * ~ServerControl() // // --------------------------------------------------------------------------- ServerControl::~ServerControl ( void ) { if ( fTCPHandlerSemaphore != nil ) { delete( fTCPHandlerSemaphore ); fTCPHandlerSemaphore = nil; } if ( fHandlerSemaphore != nil ) { delete( fHandlerSemaphore ); fHandlerSemaphore = nil; } if ( fInternalHandlerSemaphore != nil ) { delete( fInternalHandlerSemaphore ); fInternalHandlerSemaphore = nil; } if ( fCheckpwHandlerSemaphore != nil ) { delete( fCheckpwHandlerSemaphore ); fCheckpwHandlerSemaphore = nil; } } // ~ServerControl // --------------------------------------------------------------------------- // * StartUpServer () // // --------------------------------------------------------------------------- sInt32 ServerControl::StartUpServer ( void ) { sInt32 result = eDSNoErr; struct stat statResult; LDAP* aHost = nil; int rc = LDAP_SUCCESS; try { if ( gNodeList == nil ) { gNodeList = new CNodeList; if ( gNodeList == nil ) throw((sInt32)eMemoryAllocError); } if ( gRefTable == nil ) { gRefTable = new CRefTable( CHandlerThread::RefDeallocProc ); if ( gRefTable == nil ) throw( (sInt32)eMemoryAllocError ); } if ( gPlugins == nil ) { gPlugins = new CPlugInList(); if ( gPlugins == nil ) throw( (sInt32)eMemoryAllocError ); } if ( gTCPMsgQueue == nil ) { gTCPMsgQueue = new CMsgQueue; if ( gTCPMsgQueue == nil ) throw((sInt32)eMemoryAllocError); } if ( gMsgQueue == nil ) { gMsgQueue = new CMsgQueue; if ( gMsgQueue == nil ) throw((sInt32)eMemoryAllocError); } if ( gInternalMsgQueue == nil ) { gInternalMsgQueue = new CMsgQueue; if ( gInternalMsgQueue == nil ) throw((sInt32)eMemoryAllocError); } if ( gCheckpwMsgQueue == nil ) { gCheckpwMsgQueue = new CMsgQueue; if ( gCheckpwMsgQueue == nil ) throw((sInt32)eMemoryAllocError); } if (::stat( "/Library/Preferences/DirectoryService/.DSLogAPIAtStart", &statResult ) == eDSNoErr) { gLogAPICalls = true; gSunsetTime = time(nil) + 300; syslog(LOG_INFO,"Logging of API Calls turned ON at Startup of DS Daemon."); } // initialize LDAP before any plug-ins rc = ldap_initialize(&aHost, NULL); if (rc == LDAP_SUCCESS) { ldap_unbind(aHost); aHost = NULL; } // Start the listener thread result = StartListener(); if ( result != eDSNoErr ) throw( result ); if (::stat( "/Library/Preferences/DirectoryService/.DSTCPListening", &statResult ) == eDSNoErr) { // Start the TCP listener thread result = StartTCPListener(kDSDefaultListenPort); if ( result != eDSNoErr ) throw( result ); } if ( gPluginHandler == nil ) { gPluginHandler = new CPluginHandler; if ( gPluginHandler == nil ) throw((sInt32)eMemoryAllocError); //this call could throw gPluginHandler->StartThread(); } // result = RegisterForSystemPower(); // if ( result != eDSNoErr ) throw( result ); result = (sInt32)RegisterForNetworkChange(); if ( result != eDSNoErr ) throw( result ); result = SetUpPeriodicTask(); if ( result != eDSNoErr ) throw( result ); } catch( sInt32 err ) { result = err; } return( result ); } // StartUpServer // --------------------------------------------------------------------------- // * ShutDownServer () // // --------------------------------------------------------------------------- sInt32 ServerControl::ShutDownServer ( void ) { sInt32 result = eDSNoErr; uInt32 i = 0; uInt32 uiStopCnt = 0; struct stat statResult; try { result = (sInt32)UnRegisterForNetworkChange(); if ( result != eDSNoErr ) throw( result ); // result = UnRegisterForSystemPower(); // if ( result != eDSNoErr ) throw( result ); //need to stop the listener before anything else fListener->StopThread(); if (::stat( "/Library/Preferences/DirectoryService/.DSTCPListening", &statResult ) == eDSNoErr) { //need to stop the TCP listener before anything else //assume that the listener itself will close all of its connections if (fTCPListener != nil) { fTCPListener->StopThread(); gTCPHandlerLock->Wait(); // Stop the handler threads for ( i = 0; i < kMaxHandlerThreads; i++ ) { if ( fTCPHandlers[ i ] != nil ) { uiStopCnt += 1; fTCPHandlers[ i ]->StopThread(); fTCPHandlers[ i ] = nil; } } gTCPHandlerLock->Signal(); while (uiStopCnt > 0) { WakeAHandler(DSCThread::kTSTCPHandlerThread); uiStopCnt--; } uiStopCnt = 0; } } gHandlerLock->Wait(); // Stop the handler threads for ( i = 0; i < kMaxHandlerThreads; i++ ) { if ( fHandlers[ i ] != nil ) { uiStopCnt += 1; fHandlers[ i ]->StopThread(); fHandlers[ i ] = nil; } } gHandlerLock->Signal(); while (uiStopCnt > 0) { WakeAHandler(DSCThread::kTSHandlerThread); uiStopCnt--; } uiStopCnt = 0; gInternalHandlerLock->Wait(); // Stop the internal handler threads for ( i = 0; i < kMaxInternalHandlerThreads; i++ ) { if ( fInternalHandlers[ i ] != nil ) { uiStopCnt += 1; fInternalHandlers[ i ]->StopThread(); fInternalHandlers[ i ] = nil; } } gInternalHandlerLock->Signal(); while (uiStopCnt > 0) { WakeAHandler(DSCThread::kTSInternalHandlerThread); uiStopCnt--; } uiStopCnt = 0; gCheckpwHandlerLock->Wait(); // Stop the Checkpw handler threads for ( i = 0; i < kMaxCheckpwHandlerThreads; i++ ) { if ( fCheckpwHandlers[ i ] != nil ) { uiStopCnt += 1; fCheckpwHandlers[ i ]->StopThread(); fCheckpwHandlers[ i ] = nil; } } gCheckpwHandlerLock->Signal(); while (uiStopCnt > 0) { WakeAHandler(DSCThread::kTSCheckpwHandlerThread); uiStopCnt--; } if ( gNodeList != nil ) { delete( gNodeList ); gNodeList = nil; } if ( gRefTable != nil ) { delete( gRefTable ); gRefTable = nil; } if ( gPlugins != nil ) { delete( gPlugins ); gPlugins = nil; } if ( gTCPMsgQueue != nil ) { delete( gTCPMsgQueue ); gTCPMsgQueue = nil; } if ( gMsgQueue != nil ) { delete( gMsgQueue ); gMsgQueue = nil; } if ( gInternalMsgQueue != nil ) { delete( gInternalMsgQueue ); gInternalMsgQueue = nil; } if ( gCheckpwMsgQueue != nil ) { delete( gCheckpwMsgQueue ); gCheckpwMsgQueue = nil; } delete(gTCPHandlerLock); delete(gHandlerLock); delete(gInternalHandlerLock); delete(gCheckpwHandlerLock); CLog::Deinitialize(); } catch( sInt32 err ) { result = err; } return( result ); } // ShutDownServer // --------------------------------------------------------------------------- // * StartListener () // // --------------------------------------------------------------------------- sInt32 ServerControl::StartListener ( void ) { sInt32 result = eDSNoErr; try { fListener = new CListener(); if ( fListener == nil ) throw((sInt32)eMemoryAllocError); //this call could throw fListener->StartThread(); //fListenerStarted = true; } catch( sInt32 err ) { result = err; DBGLOG2( kLogApplication, "File: %s. Line: %d", __FILE__, __LINE__ ); DBGLOG1( kLogApplication, " Caught exception = %d.", err ); } if ( (result == eDSNoErr) && (gServerRunLoop != NULL) ) { //let's add in capability to clean up dead client mach ports if listener started CFMachPortRef d_port = CFMachPortCreate(NULL, ClientDeathCallback, NULL, NULL); CFRunLoopSourceRef d_rls = CFMachPortCreateRunLoopSource(NULL, d_port, 0); gClient_Death_Notify_Port = CFMachPortGetPort(d_port); CFRunLoopAddSource(gServerRunLoop, d_rls, kCFRunLoopDefaultMode); CFRelease(d_rls); //do we need to release d_port? } return( result ); } // StartListener // --------------------------------------------------------------------------- // * StartTCPListener () // // --------------------------------------------------------------------------- sInt32 ServerControl::StartTCPListener ( uInt32 inPort ) { sInt32 result = eDSNoErr; try { fTCPListener = new DSTCPListener(inPort); if ( fTCPListener == nil ) throw((sInt32)eMemoryAllocError); //this call could throw fTCPListener->StartThread(); } catch( sInt32 err ) { result = err; DBGLOG2( kLogApplication, "File: %s. Line: %d", __FILE__, __LINE__ ); DBGLOG1( kLogApplication, " Caught exception = %d.", err ); } return( result ); } // StartTCPListener // --------------------------------------------------------------------------- // * StopTCPListener () // // --------------------------------------------------------------------------- sInt32 ServerControl::StopTCPListener ( void ) { sInt32 result = eDSNoErr; try { if ( fTCPListener == nil ) throw((sInt32)eMemoryAllocError); //this call could throw fTCPListener->StopThread(); } catch( sInt32 err ) { result = err; DBGLOG2( kLogApplication, "File: %s. Line: %d", __FILE__, __LINE__ ); DBGLOG1( kLogApplication, " Caught exception = %d.", err ); } return( result ); } // StopTCPListener // --------------------------------------------------------------------------- // * StartAHandler () // // --------------------------------------------------------------------------- sInt32 ServerControl:: StartAHandler ( const FourCharCode inThreadSignature ) { volatile uInt32 iThread; sInt32 result = eDSNoErr; try { // If we have less than the max handlers then we add one //decide from which set of handlers to start one if (inThreadSignature == DSCThread::kTSTCPHandlerThread) { if ( (fTCPHandlerThreadsCnt >= 0) && (fTCPHandlerThreadsCnt < kMaxHandlerThreads) ) { for (iThread =0; iThread < kMaxHandlerThreads; iThread++) { if (fTCPHandlers[ iThread ] == nil) { // Start a handler thread fTCPHandlers[ iThread ] = new CHandlerThread(DSCThread::kTSTCPHandlerThread, iThread); if ( fTCPHandlers[ iThread ] == nil ) throw((sInt32)eMemoryAllocError); fTCPHandlerThreadsCnt++; //this call could throw fTCPHandlers[ iThread ]->StartThread(); break; } else if ( fTCPHandlers[iThread]->GetOurThreadRunState() == DSCThread::kThreadStop) { // Start a handler thread fTCPHandlers[ iThread ] = new CHandlerThread(DSCThread::kTSTCPHandlerThread, iThread); if ( fTCPHandlers[ iThread ] == nil ) throw((sInt32)eMemoryAllocError); //fTCPHandlerThreadsCnt++; //no need since replacing //this call could throw fTCPHandlers[ iThread ]->StartThread(); break; } } } } if (inThreadSignature == DSCThread::kTSHandlerThread) { if ( (fHandlerThreadsCnt >= 0) && (fHandlerThreadsCnt < kMaxHandlerThreads) ) { for (iThread =0; iThread < kMaxHandlerThreads; iThread++) { if (fHandlers[ iThread ] == nil) { // Start a handler thread fHandlers[ iThread ] = new CHandlerThread(DSCThread::kTSHandlerThread, iThread); if ( fHandlers[ iThread ] == nil ) throw((sInt32)eMemoryAllocError); fHandlerThreadsCnt++; //this call could throw fHandlers[ iThread ]->StartThread(); break; } else if ( fHandlers[iThread]->GetOurThreadRunState() == DSCThread::kThreadStop) { // Start a handler thread fHandlers[ iThread ] = new CHandlerThread(DSCThread::kTSHandlerThread, iThread); if ( fHandlers[ iThread ] == nil ) throw((sInt32)eMemoryAllocError); //fHandlerThreadsCnt++; //no need since replacing //this call could throw fHandlers[ iThread ]->StartThread(); break; } } } } if (inThreadSignature == DSCThread::kTSInternalHandlerThread) { if ( (fInternalHandlerThreadsCnt >= 0) && (fInternalHandlerThreadsCnt < kMaxInternalHandlerThreads) ) { for (iThread =0; iThread < kMaxInternalHandlerThreads; iThread++) { if (fInternalHandlers[ iThread ] == nil) { // Start a handler thread fInternalHandlers[ iThread ] = new CHandlerThread(DSCThread::kTSInternalHandlerThread, iThread); if ( fInternalHandlers[ iThread ] == nil ) throw((sInt32)eMemoryAllocError); fInternalHandlerThreadsCnt++; //this call could throw fInternalHandlers[ iThread ]->StartThread(); break; } else if ( fInternalHandlers[iThread]->GetOurThreadRunState() == DSCThread::kThreadStop) { // Start a handler thread fInternalHandlers[ iThread ] = new CHandlerThread(DSCThread::kTSInternalHandlerThread, iThread); if ( fInternalHandlers[ iThread ] == nil ) throw((sInt32)eMemoryAllocError); //fInternalHandlerThreadsCnt++; //no need since replacing //this call could throw fInternalHandlers[ iThread ]->StartThread(); break; } } } } if (inThreadSignature == DSCThread::kTSCheckpwHandlerThread) { if ( (fCheckpwHandlerThreadsCnt >= 0) && (fCheckpwHandlerThreadsCnt < kMaxCheckpwHandlerThreads) ) { for (iThread =0; iThread < kMaxCheckpwHandlerThreads; iThread++) { if (fCheckpwHandlers[ iThread ] == nil) { // Start a handler thread fCheckpwHandlers[ iThread ] = new CHandlerThread(DSCThread::kTSCheckpwHandlerThread, iThread); if ( fCheckpwHandlers[ iThread ] == nil ) throw((sInt32)eMemoryAllocError); fCheckpwHandlerThreadsCnt++; //this call could throw fCheckpwHandlers[ iThread ]->StartThread(); break; } else if ( fCheckpwHandlers[iThread]->GetOurThreadRunState() == DSCThread::kThreadStop) { // Start a handler thread fCheckpwHandlers[ iThread ] = new CHandlerThread(DSCThread::kTSCheckpwHandlerThread, iThread); if ( fCheckpwHandlers[ iThread ] == nil ) throw((sInt32)eMemoryAllocError); //fCheckpwHandlerThreadsCnt++; //no need since replacing //this call could throw fCheckpwHandlers[ iThread ]->StartThread(); break; } } } } } catch( sInt32 err ) { result = err; } return( result ); } // StartAHandler //-------------------------------------------------------------------------------------------------- // * WakeAHandler() // //-------------------------------------------------------------------------------------------------- void ServerControl:: WakeAHandler ( const FourCharCode inThreadSignature ) { if (inThreadSignature == DSCThread::kTSTCPHandlerThread) { fTCPHandlerSemaphore->Signal(); } if (inThreadSignature == DSCThread::kTSHandlerThread) { fHandlerSemaphore->Signal(); } if (inThreadSignature == DSCThread::kTSInternalHandlerThread) { fInternalHandlerSemaphore->Signal(); } if (inThreadSignature == DSCThread::kTSCheckpwHandlerThread) { fCheckpwHandlerSemaphore->Signal(); } } // WakeAHandler // --------------------------------------------------------------------------- // * StopAHandler () // // --------------------------------------------------------------------------- sInt32 ServerControl:: StopAHandler ( const FourCharCode inThreadSignature, uInt32 iThread, CHandlerThread *inThread ) { sInt32 result = eDSNoErr; try { // DBGLOG2( kLogApplication, "File: %s. Line: %d", __FILE__, __LINE__ ); // DBGLOG2( kLogApplication, "StopAHandler: sig = %d and index = %d", inThreadSignature, iThread ); if (inThreadSignature == DSCThread::kTSTCPHandlerThread) { if ( (iThread >= 0) && (iThread < kMaxHandlerThreads) ) { if (fTCPHandlers[ iThread ] == inThread) { // Remove a handler thread from the list fTCPHandlers[ iThread ] = nil; fTCPHandlerThreadsCnt--; } } } if (inThreadSignature == DSCThread::kTSHandlerThread) { if ( (iThread >= 0) && (iThread < kMaxHandlerThreads) ) { if (fHandlers[ iThread ] == inThread) { // Remove a handler thread from the list fHandlers[ iThread ] = nil; fHandlerThreadsCnt--; } } } if (inThreadSignature == DSCThread::kTSInternalHandlerThread) { if ( (iThread >= 0) && (iThread < kMaxInternalHandlerThreads) ) { if (fInternalHandlers[ iThread ] == inThread) { // Remove a handler thread from the list fInternalHandlers[ iThread ] = nil; fInternalHandlerThreadsCnt--; } } } if (inThreadSignature == DSCThread::kTSCheckpwHandlerThread) { if ( (iThread >= 0) && (iThread < kMaxCheckpwHandlerThreads) ) { if (fCheckpwHandlers[ iThread ] == inThread) { // Remove a handler thread from the list fCheckpwHandlers[ iThread ] = nil; fCheckpwHandlerThreadsCnt--; } } } } catch( sInt32 err ) { result = err; } return( result ); } // StopAHandler //-------------------------------------------------------------------------------------------------- // * SleepAHandler(const FourCharCode inThreadSignature, uInt32 waitTime) // //-------------------------------------------------------------------------------------------------- void ServerControl:: SleepAHandler ( const FourCharCode inThreadSignature, uInt32 waitTime ) { if (inThreadSignature == DSCThread::kTSTCPHandlerThread) { fTCPHandlerSemaphore->Wait( waitTime ); } if (inThreadSignature == DSCThread::kTSHandlerThread) { fHandlerSemaphore->Wait( waitTime ); } if (inThreadSignature == DSCThread::kTSInternalHandlerThread) { fInternalHandlerSemaphore->Wait( waitTime ); } if (inThreadSignature == DSCThread::kTSCheckpwHandlerThread) { fCheckpwHandlerSemaphore->Wait( waitTime ); } } // SleepAHandler //-------------------------------------------------------------------------------------------------- // * GetHandlerCount(const FourCharCode inThreadSignature) // //-------------------------------------------------------------------------------------------------- uInt32 ServerControl::GetHandlerCount ( const FourCharCode inThreadSignature ) { if (inThreadSignature == DSCThread::kTSTCPHandlerThread) { return fTCPHandlerThreadsCnt; } if (inThreadSignature == DSCThread::kTSHandlerThread) { return fHandlerThreadsCnt; } if (inThreadSignature == DSCThread::kTSInternalHandlerThread) { return fInternalHandlerThreadsCnt; } if (inThreadSignature == DSCThread::kTSCheckpwHandlerThread) { return fCheckpwHandlerThreadsCnt; } return 0; } // GetHandlerCount // --------------------------------------------------------------------------- // * RegisterForNetworkChange () // // --------------------------------------------------------------------------- sInt32 ServerControl:: RegisterForNetworkChange ( void ) { sInt32 scdStatus = eDSNoErr; CFStringRef dhcpKey = 0; //DHCP changes key CFStringRef ipKey = 0; //ip changes key CFStringRef niKey = 0; //NetInfo changes key CFStringRef atKey = 0; //Appletalk changes key // CFStringRef dnsKey = 0; //DNS changes key // CFStringRef nisKey = 0; //NIS changes key // CFStringRef computerNameKey = 0; //computer name changes key CFMutableArrayRef notifyKeys = 0; CFMutableArrayRef notifyPatterns = 0; Boolean setStatus = FALSE; CFStringRef aPIDString = 0; DBGLOG( kLogApplication, "RegisterForNetworkChange(): " ); fSCDStore = SCDynamicStoreCreate(NULL, CFSTR("DirectoryService"), NULL, NULL); //KW use constant string instead if (fSCDStore != 0) { notifyKeys = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); notifyPatterns = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); //CFArrayAppendValue(notifyPatterns, kSCCompAnyRegex); //formerly kSCDRegexKey // ip changes ipKey = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4); CFArrayAppendValue(notifyKeys, ipKey); CFRelease(ipKey); //DHCP changes dhcpKey = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetDHCP); CFArrayAppendValue(notifyPatterns, dhcpKey); CFRelease(dhcpKey); // Appletalk changes atKey = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetAppleTalk); CFArrayAppendValue(notifyKeys, atKey); CFRelease(atKey); // NetInfo changes niKey = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetNetInfo); CFArrayAppendValue(notifyKeys, niKey); CFRelease(niKey); // DNS changed //dnsKey = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS); //CFArrayAppendValue(notifyKeys, dnsKey); //CFRelease(dnsKey); // NIS changed //nisKey = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetNIS); //CFArrayAppendValue(notifyKeys, nisKey); //CFRelease(nisKey); //same mechanism that lookupd daemon currently uses to restart itself //although in our case we simply stop and allow any client through our //framework to restart us when required //CFArrayAppendValue(notifyKeys, CFSTR("File:/var/run/nibindd.pid")); // computer name changes //computerNameKey = SCDynamicStoreKeyCreateHostName(); //CFArrayAppendValue(notifyKeys, computerNameKey); setStatus = SCDynamicStoreSetNotificationKeys(fSCDStore, notifyKeys, notifyPatterns); CFRelease(notifyKeys); CFRelease(notifyPatterns); //SCDOptionSet(NULL, kSCDOptionUseCFRunLoop, FALSE); //not checking bool return SCDynamicStoreNotifyCallback( fSCDStore, gServerRunLoop, NetworkChangeCallBack, this ); //this is update code for things like NetInfo and DHCP issues //ie. calls to the search node that verify or re-establish the default NI and LDAPv3(from DHCP) nodes //send SIGHUP on a network transition //setStatus = SCDynamicStoreNotifySignal( fSCDStore, getpid(), SIGHUP); aPIDString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%d"), (uInt32)getpid()); setStatus = SCDynamicStoreAddTemporaryValue( fSCDStore, CFSTR("DirectoryService:PID"), aPIDString ); CFRelease(aPIDString); } // SCDSessionRef okay return scdStatus; } // RegisterForNetworkChange // --------------------------------------------------------------------------- // * UnRegisterForNetworkChange () // // --------------------------------------------------------------------------- sInt32 ServerControl:: UnRegisterForNetworkChange ( void ) { sInt32 scdStatus = eDSNoErr; DBGLOG( kLogApplication, "UnRegisterForNetworkChange(): " ); if (fSCDStore != 0) { CFRelease(fSCDStore); fSCDStore = 0; } return scdStatus; } // UnRegisterForNetworkChange // --------------------------------------------------------------------------- // * RegisterForSystemPower () // // --------------------------------------------------------------------------- sInt32 ServerControl::RegisterForSystemPower ( void ) { IONotificationPortRef pmNotificationPortRef; DBGLOG( kLogApplication, "RegisterForSystemPower(): " ); gPMKernelPort = IORegisterForSystemPower(this, &pmNotificationPortRef, dsPMNotificationHandler, &gPMDeregisterNotifier); if (gPMKernelPort == nil) { DBGLOG( kLogApplication, "RegisterForSystemPower(): IORegisterForSystemPower failed" ); } return (gPMKernelPort != nil) ? eDSNoErr : -1; } // RegisterForSystemPower // --------------------------------------------------------------------------- // * UnRegisterForSystemPower () // // --------------------------------------------------------------------------- sInt32 ServerControl::UnRegisterForSystemPower ( void ) { sInt32 ioResult = eDSNoErr; DBGLOG( kLogApplication, "UnRegisterForSystemPower(): " ); if (gPMKernelPort != nil) { gPMKernelPort = nil; ioResult = (sInt32)IODeregisterForSystemPower(&gPMDeregisterNotifier); if (ioResult != eDSNoErr) { DBGLOG1( kLogApplication, "UnRegisterForSystemPower(): IODeregisterForSystemPower failed, error= %d", ioResult ); } } return ioResult; } // UnRegisterForSystemPower // --------------------------------------------------------------------------- // * HandleNetworkTransition () // // --------------------------------------------------------------------------- sInt32 ServerControl::HandleNetworkTransition ( void ) { sInt32 siResult = eDSNoErr; uInt32 iterator = 0; CServerPlugin *pPlugin = nil; sHeader aHeader; CPlugInList::sTableData *pPIInfo = nil; CServerPlugin *searchPlugin = nil; uInt32 searchIterator = 0; aHeader.fType = kHandleNetworkTransition; aHeader.fResult = eDSNoErr; aHeader.fContextData = nil; SRVRLOG( kLogApplication, "Network transition occurred." ); //call thru to each plugin if ( gPlugins != nil ) { pPlugin = gPlugins->Next( &iterator ); while (pPlugin != nil) { pPIInfo = gPlugins->GetPlugInInfo( iterator-1 ); if (pPIInfo->fState & kActive) //only notify Active plugins { if ( ::strcmp(pPIInfo->fName,"Search") != 0) { siResult = eDSNoErr; siResult = pPlugin->ProcessRequest( (void*)&aHeader ); if (siResult != eDSNoErr) { if (pPIInfo != nil) { ERRORLOG2( kLogApplication, "Network transition in %s plugin returned error %d", pPIInfo->fName, siResult ); } else { ERRORLOG1( kLogApplication, "Network transition of unnamed plugin returned error %d", siResult ); } } } else { searchIterator = iterator; searchPlugin = pPlugin; } } pPlugin = gPlugins->Next( &iterator ); } } //handle the search plugin transition last to ensure at least NetInfo and LDAPv3 have gone first if (searchPlugin != nil) { pPIInfo = gPlugins->GetPlugInInfo( searchIterator-1 ); siResult = eDSNoErr; siResult = searchPlugin->ProcessRequest( (void*)&aHeader ); if (siResult != eDSNoErr) { if (pPIInfo != nil) { ERRORLOG1( kLogApplication, "Network transition in Search returned error %d", siResult ); } } } return siResult; } // HandleNetworkTransition // --------------------------------------------------------------------------- // * SetUpPeriodicTask () // // --------------------------------------------------------------------------- sInt32 ServerControl::SetUpPeriodicTask ( void ) { sInt32 siResult = eDSNoErr; void *ptInfo = nil; CFRunLoopTimerContext c = {0, (void*)ptInfo, NULL, NULL, PeriodicTaskCopyStringCallback}; CFRunLoopTimerRef timer = CFRunLoopTimerCreate( NULL, CFAbsoluteTimeGetCurrent() + 120, 120, 0, 0, DoPeriodicTask, (CFRunLoopTimerContext*)&c); CFRunLoopAddTimer(gServerRunLoop, timer, kCFRunLoopDefaultMode); if (timer) CFRelease(timer); return siResult; } // SetUpPeriodicTask // --------------------------------------------------------------------------- // * DoPeriodicTask () // // --------------------------------------------------------------------------- void DoPeriodicTask(CFRunLoopTimerRef timer, void *info) { sInt32 siResult = eDSNoErr; uInt32 iterator = 0; CServerPlugin *pPlugin = nil; CPlugInList::sTableData *pPIInfo = nil; //call thru to each plugin if ( gPlugins != nil ) { pPlugin = gPlugins->Next( &iterator ); while (pPlugin != nil) { pPIInfo = gPlugins->GetPlugInInfo( iterator-1 ); siResult = eDSNoErr; siResult = pPlugin->PeriodicTask(); if (siResult != eDSNoErr) { if (pPIInfo != nil) { DBGLOG2( kLogApplication, "Periodic Task in %s plugin returned error %d", pPIInfo->fName, siResult ); } else { DBGLOG1( kLogApplication, "Periodic Task of unnamed plugin returned error %d", siResult ); } } pPlugin = gPlugins->Next( &iterator ); } } return; } // DoPeriodicTask