//============================================================================= // rRwLock API //============================================================================= rRwLock rRwLock_create ( ) { _rRwLock* lock; lock = rpal_memory_alloc( sizeof( *lock ) ); if( rpal_memory_isValid( lock ) ) { lock->evtCanRead = rEvent_create( TRUE ); lock->evtCanWrite = rEvent_create( TRUE ); lock->stateLock = rMutex_create(); lock->readCount = 0; if( !rpal_memory_isValid( lock->evtCanRead ) || !rpal_memory_isValid( lock->evtCanWrite ) || !rpal_memory_isValid( lock->stateLock ) ) { rEvent_free( lock->evtCanRead ); rEvent_free( lock->evtCanWrite ); rMutex_free( lock->stateLock ); rpal_memory_free( lock ); lock = NULL; } else { rEvent_set( lock->evtCanRead ); } } return (rRwLock)lock; }
static RVOID shutdownCollectors ( ) { RU32 i = 0; if( !rEvent_wait( g_hbs_state.isTimeToStop, 0 ) ) { rpal_debug_info( "signaling to collectors to stop." ); rEvent_set( g_hbs_state.isTimeToStop ); if( NULL != g_hbs_state.hThreadPool ) { rpal_debug_info( "destroying collector thread pool." ); rThreadPool_destroy( g_hbs_state.hThreadPool, TRUE ); g_hbs_state.hThreadPool = NULL; for( i = 0; i < ARRAY_N_ELEM( g_collectors ); i++ ) { if( g_collectors[ i ].isEnabled ) { rpal_debug_info( "cleaning up collector %d.", i ); g_collectors[ i ].cleanup( &g_hbs_state, g_collectors[ i ].conf ); rSequence_free( g_collectors[ i ].conf ); g_collectors[ i ].conf = NULL; } } } } }
RBOOL rRwLock_read_unlock ( rRwLock lock ) { RBOOL isSuccess = FALSE; _rRwLock* lck = (_rRwLock*)lock; if( rpal_memory_isValid( lock ) ) { if( rMutex_lock( lck->stateLock ) ) { lck->readCount--; if( 0 == lck->readCount ) { rEvent_set( lck->evtCanWrite ); } rMutex_unlock( lck->stateLock ); isSuccess = TRUE; } } return isSuccess; }
BOOL ctrlHandler ( DWORD type ) { BOOL isHandled = FALSE; static RU32 isHasBeenSignaled = 0; UNREFERENCED_PARAMETER( type ); if( 0 == rInterlocked_set32( &isHasBeenSignaled, 1 ) ) { // We handle all events the same way, cleanly exit rpal_debug_info( "terminating rpHCP." ); rpHostCommonPlatformLib_stop(); rEvent_set( g_timeToQuit ); isHandled = TRUE; } return isHandled; }
RBOOL stopAllModules ( ) { RBOOL isSuccess = TRUE; RU32 moduleIndex = 0; for( moduleIndex = 0; moduleIndex < RP_HCP_CONTEXT_MAX_MODULES; moduleIndex++ ) { rpal_debug_info( "stopping module at %d", moduleIndex ); if( 0 != g_hcpContext.modules[ moduleIndex ].hThread ) { if( rEvent_set( g_hcpContext.modules[ moduleIndex ].isTimeToStop ) && rpal_thread_wait( g_hcpContext.modules[ moduleIndex ].hThread, RP_HCP_CONTEXT_MODULE_TIMEOUT ) ) { _cleanupModuleEntry( &( g_hcpContext.modules[ moduleIndex ] ) ); rpal_debug_info( "finished stopping module." ); } else { isSuccess = FALSE; } } } rpal_debug_info( "finished stopping all modules" ); return isSuccess; }
RBOOL rpHostCommonPlatformLib_unload ( RU8 moduleId ) { RBOOL isSuccess = FALSE; RU32 moduleIndex = 0; for( moduleIndex = 0; moduleIndex < RP_HCP_CONTEXT_MAX_MODULES; moduleIndex++ ) { if( moduleId == g_hcpContext.modules[ moduleIndex ].id ) { if( rEvent_set( g_hcpContext.modules[ moduleIndex ].isTimeToStop ) && rpal_thread_wait( g_hcpContext.modules[ moduleIndex ].hThread, (30*1000) ) ) { isSuccess = TRUE; #ifdef RPAL_PLATFORM_WINDOWS FreeLibrary( (HMODULE)g_hcpContext.modules[ moduleIndex ].hModule ); #elif defined( RPAL_PLATFORM_LINUX ) || defined( RPAL_PLATFORM_MACOSX ) dlclose( g_hcpContext.modules[ moduleIndex ].hModule ); #endif rEvent_free( g_hcpContext.modules[ moduleIndex ].context.isTimeToStop ); rpal_thread_free( g_hcpContext.modules[ moduleIndex ].hThread ); } break; } } return isSuccess; }
RBOOL stopBeacons ( ) { RBOOL isSuccess = FALSE; if( NULL != g_hcpContext.isBeaconTimeToStop ) { rEvent_set( g_hcpContext.isBeaconTimeToStop ); if( 0 != g_hcpContext.hBeaconThread ) { rpal_thread_wait( g_hcpContext.hBeaconThread, MSEC_FROM_SEC( 40 ) ); rpal_thread_free( g_hcpContext.hBeaconThread ); isSuccess = TRUE; } rEvent_free( g_hcpContext.isBeaconTimeToStop ); g_hcpContext.isBeaconTimeToStop = NULL; } return isSuccess; }
RPRIVATE_TESTABLE RBOOL unloadModule ( rpHCPContext* hcpContext, rSequence seq ) { RBOOL isSuccess = FALSE; RpHcp_ModuleId moduleId = (RU8)(-1); RU32 moduleIndex = (RU32)(-1); if( NULL != seq && NULL != hcpContext ) { if( rSequence_getRU8( seq, RP_TAGS_HCP_MODULE_ID, &moduleId ) ) { for( moduleIndex = 0; moduleIndex < RP_HCP_CONTEXT_MAX_MODULES; moduleIndex++ ) { if( moduleId == hcpContext->modules[ moduleIndex ].id ) { break; } } } } if( (RU32)(-1) != moduleIndex && RP_HCP_CONTEXT_MAX_MODULES != moduleIndex ) { #ifdef RP_HCP_LOCAL_LOAD if( hcpContext->modules[ moduleIndex ].isOsLoaded ) { // We do not unload modules loaded by the OS in debug since // they are used to debug modules during development. return FALSE; } #endif if( rEvent_set( hcpContext->modules[ moduleIndex ].isTimeToStop ) && rpal_thread_wait( hcpContext->modules[ moduleIndex ].hThread, ( 30 * 1000 ) ) ) { isSuccess = TRUE; _cleanupModuleEntry( &( hcpContext->modules[ moduleIndex ] ) ); } } return isSuccess; }
void ctrlHandler ( int sigNum ) { static RU32 isHasBeenSignaled = 0; if( 0 == rInterlocked_set32( &isHasBeenSignaled, 1 ) ) { rpal_debug_info( "terminating rpHCP." ); rpHostCommonPlatformLib_stop(); rEvent_set( g_timeToQuit ); } }
RBOOL rRwLock_write_unlock ( rRwLock lock ) { RBOOL isSuccess = FALSE; _rRwLock* lck = (_rRwLock*)lock; if( rpal_memory_isValid( lock ) ) { rEvent_set( lck->evtCanRead ); rMutex_unlock( lck->stateLock ); isSuccess = TRUE; } return isSuccess; }
static VOID WINAPI SvcCtrlHandler ( DWORD fdwControl ) { switch( fdwControl ) { case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_SHUTDOWN: if( g_svc_status.dwCurrentState != SERVICE_RUNNING ) break; /* * Perform tasks necessary to stop the service here */ g_svc_status.dwControlsAccepted = 0; g_svc_status.dwCurrentState = SERVICE_STOP_PENDING; g_svc_status.dwWin32ExitCode = 0; g_svc_status.dwCheckPoint = 2; SetServiceStatus( g_svc_status_handle, &g_svc_status ); rpal_debug_info( "terminating rpHCP." ); rpHostCommonPlatformLib_stop(); rEvent_set( g_timeToQuit ); break; default: break; } }
//============================================================================= // Entry Point //============================================================================= RU32 RPAL_THREAD_FUNC RpHcpI_mainThread ( rEvent isTimeToStop ) { RU32 ret = 0; RU64 nextBeaconTime = 0; rList cloudMessages = NULL; rSequence msg = NULL; rList newConfigurations = NULL; rList newNotifications = NULL; RPU8 newConfigurationHash = NULL; RU32 newHashSize = 0; rSequence staticConfig = NULL; RU8* tmpBuffer = NULL; RU32 tmpSize = 0; FORCE_LINK_THAT( HCP_IFACE ); CryptoLib_init(); getPrivileges(); // This is the event for the collectors, it is different than the // hbs proper event so that we can restart the collectors without // signaling hbs as a whole. if( NULL == ( g_hbs_state.isTimeToStop = rEvent_create( TRUE ) ) ) { return (RU32)-1; } // By default, no collectors are running rEvent_set( g_hbs_state.isTimeToStop ); // We attempt to load some initial config from the serialized // rSequence that can be patched in this binary. if( NULL != ( staticConfig = getStaticConfig() ) ) { if( rSequence_getBUFFER( staticConfig, RP_TAGS_HBS_ROOT_PUBLIC_KEY, &tmpBuffer, &tmpSize ) ) { hbs_cloud_pub_key = rpal_memory_duplicate( tmpBuffer, tmpSize ); if( NULL == hbs_cloud_pub_key ) { hbs_cloud_pub_key = hbs_cloud_default_pub_key; } rpal_debug_info( "loading hbs root public key from static config" ); } if( rSequence_getRU32( staticConfig, RP_TAGS_MAX_QUEUE_SIZE, &g_hbs_state.maxQueueNum ) ) { rpal_debug_info( "loading max queue size from static config" ); } else { g_hbs_state.maxQueueNum = HBS_EXFIL_QUEUE_MAX_NUM; } if( rSequence_getRU32( staticConfig, RP_TAGS_MAX_SIZE, &g_hbs_state.maxQueueSize ) ) { rpal_debug_info( "loading max queue num from static config" ); } else { g_hbs_state.maxQueueSize = HBS_EXFIL_QUEUE_MAX_SIZE; } rSequence_free( staticConfig ); } else { hbs_cloud_pub_key = hbs_cloud_default_pub_key; g_hbs_state.maxQueueNum = HBS_EXFIL_QUEUE_MAX_NUM; g_hbs_state.maxQueueSize = HBS_EXFIL_QUEUE_MAX_SIZE; } if( !rQueue_create( &g_hbs_state.outQueue, freeExfilEvent, g_hbs_state.maxQueueNum ) ) { rEvent_free( g_hbs_state.isTimeToStop ); return (RU32)-1; } // We simply enqueue a message to let the cloud know we're starting sendStartupEvent(); while( !rEvent_wait( isTimeToStop, (RU32)nextBeaconTime ) ) { nextBeaconTime = MSEC_FROM_SEC( HBS_DEFAULT_BEACON_TIMEOUT + ( rpal_rand() % HBS_DEFAULT_BEACON_TIMEOUT_FUZZ ) ); if( NULL != ( cloudMessages = beaconHome() ) ) { while( rList_getSEQUENCE( cloudMessages, RP_TAGS_MESSAGE, &msg ) ) { // Cloud message indicating next requested beacon time, as a Seconds delta if( rSequence_getTIMEDELTA( msg, RP_TAGS_TIMEDELTA, &nextBeaconTime ) ) { nextBeaconTime = MSEC_FROM_SEC( nextBeaconTime ); rpal_debug_info( "received set_next_beacon" ); } if( NULL == newConfigurations && rSequence_getLIST( msg, RP_TAGS_HBS_CONFIGURATIONS, &newConfigurations ) ) { rpal_debug_info( "received a new profile" ); if( rSequence_getBUFFER( msg, RP_TAGS_HASH, &newConfigurationHash, &newHashSize ) && newHashSize == CRYPTOLIB_HASH_SIZE ) { newConfigurations = rList_duplicate( newConfigurations ); rpal_memory_memcpy( &( g_hbs_state.currentConfigHash ), newConfigurationHash, CRYPTOLIB_HASH_SIZE ); g_hbs_state.isProfilePresent = TRUE; } else { newConfigurations = NULL; rpal_debug_error( "profile hash received is invalid" ); } } if( NULL == newNotifications && rSequence_getLIST( msg, RP_TAGS_HBS_CLOUD_NOTIFICATIONS, &newNotifications ) ) { rpal_debug_info( "received cloud events" ); newNotifications = rList_duplicate( newNotifications ); } } rList_free( cloudMessages ); } // If this is the initial boot and we have no profile yet, we'll load a dummy // blank profile and use our defaults. if( NULL == newConfigurations && !g_hbs_state.isProfilePresent && !rEvent_wait( isTimeToStop, 0 ) ) { newConfigurations = rList_new( RP_TAGS_HCP_MODULES, RPCM_SEQUENCE ); rpal_debug_info( "setting empty profile" ); } if( NULL != newConfigurations ) { // We try to be as responsive as possible when asked to quit // so if we happen to have received the signal during a beacon // we will action the quit instead of the config change. if( !rEvent_wait( isTimeToStop, 0 ) ) { rpal_debug_info( "begining sensor update on new profile" ); shutdownCollectors(); updateCollectorConfigs( newConfigurations ); rList_free( newConfigurations ); newConfigurations = NULL; startCollectors(); } else { rList_free( newConfigurations ); } newConfigurations = NULL; } if( NULL != newNotifications ) { if( !rEvent_wait( isTimeToStop, 0 ) ) { publishCloudNotifications( newNotifications ); } rList_free( newNotifications ); newNotifications = NULL; } } // We issue one last beacon indicating we are stopping sendShutdownEvent(); // Shutdown everything shutdownCollectors(); // Cleanup the last few resources rEvent_free( g_hbs_state.isTimeToStop ); rQueue_free( g_hbs_state.outQueue ); CryptoLib_deinit(); if( hbs_cloud_default_pub_key != hbs_cloud_pub_key && NULL != hbs_cloud_pub_key ) { rpal_memory_free( hbs_cloud_pub_key ); hbs_cloud_pub_key = NULL; } return ret; }