////////////////////////////////////////////////////////////////////////////////////
///
///   \brief Prints status info about the Service to the console.
///
////////////////////////////////////////////////////////////////////////////////////
void AccessControl::PrintStatus() const
{
    //Mutex::ScopedLock lock(&mControlMutex);
    
    std::cout << "[" << GetServiceID().ToString() << "] - " << GetComponentID().ToString() << "\n";

    Address controller;
    Byte authority;
    Address::Set controlled;
    std::map<Address, bool> flags;

    mControlMutex.Lock();
    controller = mControllerID;
    authority = mControllerAuthorityCode;
    controlled = mControlledComponents;
    flags = mControlFlags;
    mControlMutex.Unlock();

    if(controller.IsValid())
    {
        std::cout << "Controlled by: " 
                  << controller.ToString() 
                  << " Authority Code: " 
                  << (int)authority << std::endl;
    }
    if(controlled.size() > 0)
    {
        Address::Set::const_iterator c;
        std::cout << "In Control of the Following:\n";
        for(c = controlled.begin();
            c != controlled.end();
            c++)
        {
            if(flags.find(*c)->second)
            {
                std::cout << " - " << c->ToString() << std::endl;
            }
        }
    }
}
////////////////////////////////////////////////////////////////////////////////////
///
///   \brief Method to release exclusive control of a component.
///
///   \param[in] id The ID of the component to request control of.  If ID is
///                 invalid (all zeros), then control is released to all
///                 components.
///   \param[in] waitTimeMs How long to wait for a response in milliseconds
///                         from the component being requested.
///
///   \return True if control is established, otherwise false.
///
////////////////////////////////////////////////////////////////////////////////////
bool AccessControl::ReleaseComponentControl(const Address& id, 
                                            const unsigned int waitTimeMs)
{
    bool result = false;

    if(id.IsValid() == false)
    {
        result = true;
        Address::Set controlled;
        mControlMutex.Lock();
        controlled = mControlledComponents;
        mControlMutex.Unlock();
        Address::Set::iterator component;
        for(component = controlled.begin();
            component != controlled.end();
            component++)
        {
            result &= ReleaseComponentControl(*component, waitTimeMs);
        }
    }
    else
    {
        std::map<Address, bool>::iterator flag;
        mControlMutex.Lock();
        flag = mControlFlags.find(id);
        if(flag != mControlFlags.end())
        {
            // If we lost control at some point, then
            // we don't need to release it, just remove
            // the component from our lists.
            if(flag->second == false)
            {
                result = true;
                // Remove the component from our lists.
                EraseComponentControlInfo(id);
            }
        }
        else
        {
            // Can't release control of a component
            // we never requested control from.
            result = true;
            EraseComponentControlInfo(id);
        }
        mControlMutex.Unlock();

        if(!result)
        {
            // Signal control routines to not
            // try and maintain control for this component anymore.
            mControlMutex.Lock();
            mToReleaseControl.insert(id);
            mControlMutex.Unlock();
            // Send request to release control, and verify response.
            ReleaseControl release(id, GetComponentID());

            RejectControl reject;

            if(Send(&release, &reject, waitTimeMs))
            {
                if(reject.GetResponseCode() == RejectControl::ControlReleased)
                {
                    result = true;
                    Mutex::ScopedLock lock(&mControlMutex);
                    EraseComponentControlInfo(id);
                }
            }

            // Remove ID.
            mControlMutex.Lock();
            mToReleaseControl.erase(mToReleaseControl.find(id));
            mControlMutex.Unlock();
        }
    }
    return result;
}
Exemple #3
0
////////////////////////////////////////////////////////////////////////////////////
///
///   \brief Method called periodically by external classes and is used to
///          verify control of components.
///
///   \param[in] timeSinceLastCheckMs Number of milliseconds since the last time
///                                   this method was called.
///
////////////////////////////////////////////////////////////////////////////////////
void AccessControl::CheckServiceStatus(const unsigned int timeSinceLastCheckMs)
{
    RequestControl request;
    Address::Set lostComponents;
    Time currentTime;

    // Upgrade/Read lock
    {
#ifdef JAUS_USE_UPGRADE_LOCKS
        UpgradeLock uLock(mControlMutex);
#else
        WriteLock wLock(mControlMutex);
#endif

        request.SetSourceID(GetComponentID());
        request.SetAuthorityCode(mAuthorityCode);

        Address::Set::iterator component;
        
        currentTime.SetCurrentTime();
    
        for(component = mControlledComponents.begin();
            component != mControlledComponents.end();
            component++)
        {
            // If we are releasing control, do not check.
            if(mToReleaseControl.find(*component) != mToReleaseControl.end())
            {
                continue;
            }
            // If we have not checked within timeout - .x seconds, then re-acquire control to
            // maintain constant control of component.
            double thresh = mTimeoutPeriods[*component]*mTimeoutThreshold/100.0;
            double checkTimeDiff = currentTime.ToSeconds() - mControlCheckTimes[*component].ToSeconds();
            double timeThresh = (mTimeoutPeriods[*component] - thresh);
            bool checkConfirmation = true;
            if(mTimeoutPeriods[*component] > 0 && checkTimeDiff >= thresh)
            {
                request.SetDestinationID(*component);
                if(Send(&request))
                {
                    // Update the check time.
#ifdef JAUS_USE_UPGRADE_LOCKS
                    UpgradeToUniqueLock upLock(uLock);
#endif
                    mControlCheckTimes[*component].SetCurrentTime();
                    checkConfirmation = false;
                }
            }
            double confirmTimeDiff = currentTime.ToSeconds() - mControlConfirmTimes[*component].ToSeconds();
            timeThresh = (mTimeoutPeriods[*component] + thresh);
            // If we haven't been confirmed in this time, then we have lost control.
            if(checkConfirmation && confirmTimeDiff > timeThresh)
            {
                mControlFlags[*component] = false;
                lostComponents.insert(*component);
            }
        }
    
    }

    // Notify subscribers of any lost control events.
    {
        Address::Set::iterator lost;
        for(lost = lostComponents.begin();
            lost != lostComponents.end();
            lost++)
        {
            // Generate events and callbacks.
            ReadLock cbrLock(mCallbacksMutex);
            Callback::Set::iterator cb;
            for(cb = mCallbacks.begin();
                cb != mCallbacks.end();
                cb++)
            {
                (*cb)->ProcessLossOfControl(*lost);
            }
        }
    }

    Address controller; // Current controlling component. 

    bool timeout = false;
    {
#ifdef JAUS_USE_UPGRADE_LOCKS
        UpgradeLock uLock(mControlMutex);
#else
        WriteLock wLock(mControlMutex);
#endif

        controller = mControllerID;
        
        currentTime.SetCurrentTime();
        double timeSinceRequest = currentTime - mControllerCheckTime;
        if(mTimeoutPeriod > 0 && 
           controller.IsValid() && 
           timeSinceRequest >= (double)mTimeoutPeriod + mTimeoutPeriod*mTimeoutThreshold/100.0)
        {
            timeout = true;
            // Release control due to timeout.
            RejectControl reject(controller, GetComponentID());
            reject.SetResponseCode(RejectControl::ControlReleased);
            Send(&reject);
            if(DebugMessagesEnabled())
            {
                std::stringstream dMessage;
                dMessage << "[" << GetServiceID().ToString() << "-" << mComponentID.ToString() 
                    << "] - Control Time from " << controller.ToString() << " at " << Time::GetUtcTime().ToString();
                PrintDebugMessage(dMessage.str());
            }

            {
#ifdef JAUS_USE_UPGRADE_LOCKS
                UpgradeToUniqueLock upLock(uLock);
#endif
                // Clear values.
                mControllerID.Clear();
                mControllerAuthorityCode = 0;
                mControllerCheckTime.Clear();
                mControllerUpdateTime.Clear();
            }
        }
    }

    if(timeout)
    {
        {
            ReadLock cbrLock(mCallbacksMutex);
            Callback::Set::iterator cb;
            for(cb = mCallbacks.begin();
                cb != mCallbacks.end();
                cb++)
            {
                (*cb)->ProcessReleaseOfControl(controller);
            }
        }
        Service::Map children = GetChildServices();
        Service::Map::iterator child;
        for(child = children.begin();
            child != children.end();
            child++)
        {
            Child* controlChild = dynamic_cast<Child *>(child->second);
            if(controlChild)
            {
                controlChild->ReleaseControl();
            }
        }
        SignalEvent(REPORT_CONTROL);
    }
}