////////////////////////////////////////////////////////////////////////////////////
///
///   \brief Processes message received by the Service.  If not supported, then
///          message is passed to inheriting services depending on what
///          type of control has been established for the component.
///
///   This Service supports AccessControl related messages only.
///
///   \param[in] message Message data to process.
///
////////////////////////////////////////////////////////////////////////////////////
void AccessControl::Receive(const Message* message)
{
    if(AcceptCommandMessage(message) == false)
    {
        return;
    }

    if(mControllerID == message->GetSourceID())
    {
        mControllerUpdateTime.SetCurrentTime();
    }

    switch(message->GetMessageCode())
    {
    case CONFIRM_CONTROL:
        {
            const ConfirmControl* command = dynamic_cast<const ConfirmControl*>(message);
            if(command == NULL)
                return;
            
            if(command->GetResponseCode() == ConfirmControl::ControlAccepted)
            {
                bool firstTime = true;

                // Lock data.
                mControlMutex.Lock();
                // See if we already had control, and if not, then
                // we re-acquired control of this component and must
                // signal via callbacks, etc. of this event.
                Address::Set::iterator controlledComponent = mControlledComponents.find(message->GetSourceID());
                if(controlledComponent != mControlledComponents.end())
                {
                    // If we get here, we have been trying to control this
                    // component. Check the control status flag.
                    std::map<Address, bool>::iterator flag = mControlFlags.find(message->GetSourceID());
                    if(flag->second == true)
                    {
                        // We already had control, nothing new here.
                        // So don't trigger events.
                        firstTime = false;
                    }
                }

                mControlledComponents.insert(message->GetSourceID());
                mControlConfirmTimes[message->GetSourceID()].SetCurrentTime();
                mControlFlags[message->GetSourceID()] = true;

                // Unlock data.
                mControlMutex.Unlock();

                if(mDebugMessagesFlag)
                {
                    Mutex::ScopedLock plock(&mDebugMessagesMutex);
                    if(firstTime)
                    {
                        std::cout << "[" << GetServiceID().ToString() << "-" << mComponentID.ToString() 
                                  << "] - Acquired Control of " << message->GetSourceID().ToString() << " at " << Time::GetUtcTime().ToString() << "\n";
                    }
                    else
                    {
                        std::cout << "[" << GetServiceID().ToString() << "-" << mComponentID.ToString() 
                                  << "] - Maintained Control of " << message->GetSourceID().ToString() << " at " << Time::GetUtcTime().ToString() << "\n";
                    }
                }

                // Trigger callbacks if needed.
                if(firstTime)
                {
                    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->ProcessAcquisitionOfControl(message->GetSourceID());
                        }
                    }

                    Mutex::ScopedLock cbLock(&mCallbacksMutex);
                    Callback::Set::iterator cb;
                    for(cb = mCallbacks.begin();
                        cb != mCallbacks.end();
                        cb++)
                    {
                        (*cb)->ProcessAcquisitionfControl(message->GetSourceID());
                    }
                }
            }
            else
            {
                Address::Set::iterator component;

                // Lock data.
                mControlMutex.Lock();

                component = mControlledComponents.find(message->GetSourceID());
                if(component != mControlledComponents.end())
                {                    
                    std::map<Address, bool>::iterator flag;
                    flag = mMaintainFlags.find(message->GetSourceID());
                    if(flag != mMaintainFlags.end())
                    {
                        // If we didn't get control, and we are not
                        // trying to maintain control, remove the component
                        // from our lists. If we don't have high enough authority
                        // then don't bother trying to re-acquire control.
                        if(flag->second == false || command->GetMessageCode() == ConfirmControl::InsufficientAuthority)
                        {
                            EraseComponentControlInfo(message->GetSourceID());
                        }
                        else // Update control status
                        {
                            mControlFlags[message->GetSourceID()] = false;
                        }
                    }
                    // Delete junk data.
                    else
                    {
                        EraseComponentControlInfo(message->GetSourceID());
                    }
                }
                // Unlock data.
                mControlMutex.Unlock();
            }
        }
        break;
    case QUERY_AUTHORITY:
        {
            if(mShutdownServiceFlag)
            {
                break;
            }
            Mutex::ScopedLock lock(&mControlMutex);
            ReportAuthority report(message->GetSourceID(), GetComponentID());
            report.SetAuthorityCode(mAuthorityCode);
            Send(&report);
        }
        break;
    case QUERY_CONTROL:
        {
            Mutex::ScopedLock lock(&mControlMutex);
            ReportControl report(message->GetSourceID(), GetComponentID());
            report.SetAuthorityCode(mControllerAuthorityCode);
            report.SetControllingComponent(mControllerID);
            Send(&report);
        } 
        break;
    case QUERY_TIMEOUT:
        {
            Mutex::ScopedLock lock(&mControlMutex);
            ReportTimeout report(message->GetSourceID(), GetComponentID());
            report.SetTimeoutSeconds(mTimeoutPeriod);
            Send(&report);
        }
        break;
    case REJECT_CONTROL:
        {
            const RejectControl* command = dynamic_cast<const RejectControl*>(message);
            if(mShutdownServiceFlag || command == NULL)
                return;

            Mutex::ScopedLock lock(&mControlMutex);

            Address::Set::iterator component;
            component = mControlledComponents.find(message->GetSourceID());
            if(component != mControlledComponents.end())
            {                
                std::map<Address, bool>::iterator flag;
                flag = mMaintainFlags.find(message->GetSourceID());
                if(flag != mMaintainFlags.end())
                {
                    // If we lost control, and we are not
                    // trying to maintain control, remove the component
                    // from our lists.
                    if(flag->second == false)
                    {
                        mMaintainFlags.erase(flag);
                        mControlFlags.erase(mControlFlags.find(message->GetSourceID()));
                        mControlConfirmTimes.erase(mControlConfirmTimes.find(message->GetSourceID()));
                        mControlledComponents.erase(component);
                    }
                    else // Update control status
                    {
                        mControlFlags[message->GetSourceID()] = false;
                    }
                    // Generate events and callbacks.
                    Mutex::ScopedLock clock(&mCallbacksMutex);
                    Callback::Set::iterator cb;
                    for(cb = mCallbacks.begin();
                        cb != mCallbacks.end();
                        cb++)
                    {
                        (*cb)->ProcessLossOfControl(message->GetSourceID());
                    }
                }
                // Delete junk data.
                else
                {
                    if(mControlFlags.find(*component) != mControlFlags.end())
                    {
                        mControlFlags.erase(*component);
                    }
                    mControlledComponents.erase(*component);
                }
            }
            if(mDebugMessagesFlag)
            {
                Mutex::ScopedLock plock(&mDebugMessagesMutex);
                std::cout << "[" << GetServiceID().ToString() << "-" << mComponentID.ToString() 
                          << "] - Lost Control of " << message->GetSourceID().ToString() << " at " << Time::GetUtcTime().ToString() << "\n";
            }
        }
        break;
    case RELEASE_CONTROL:
        {
            const ReleaseControl* command = dynamic_cast<const ReleaseControl*>(message);
            if(mShutdownServiceFlag || command == NULL)
                return;
            
            Mutex::ScopedLock lock(&mControlMutex);
            if(command->GetSourceID() == mControllerID)
            {
                RejectControl response(mControllerID, GetComponentID());

                bool controlReleased = true;
                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)
                    {
                        if(controlChild->ReleaseControl())
                        {
                            controlReleased;
                        }
                    }
                }
                if(controlReleased)
                {
                    response.SetResponseCode(RejectControl::ControlReleased);
                    Send(&response);

                    mControllerID = Address();
                    mControllerAuthorityCode = 0;
                    mControllerUpdateTime.Clear();
                    mControllerCheckTime.Clear();

                    if(mDebugMessagesFlag)
                    {
                        Mutex::ScopedLock plock(&mDebugMessagesMutex);
                        std::cout << "[" << GetServiceID().ToString() << "-" << mComponentID.ToString() 
                                  << "] - Control Released from " << message->GetSourceID().ToString() << " at " << Time::GetUtcTime().ToString() << "\n";
                    }

                    // Generate events and callbacks.
                    Mutex::ScopedLock clock(&mCallbacksMutex);
                    Callback::Set::iterator cb;
                    for(cb = mCallbacks.begin();
                        cb != mCallbacks.end();
                        cb++)
                    {
                        (*cb)->ProcessReleaseOfControl(message->GetSourceID());
                    }
                    SignalEvent(REPORT_CONTROL);
                }
                else
                {
                    response.SetResponseCode(RejectControl::NotAvailable);
                    Send(&response);
                }
            }
        }
        break;
    case REPORT_AUTHORITY:
        {
            const JAUS::ReportAuthority* report = dynamic_cast<const JAUS::ReportAuthority*>(message);
            if(report)
            {
                // Update Discovery Contents.
                try
                {
                    Discovery* discovery = GetComponent()->DiscoveryService();
                    if(discovery)
                    {
                        discovery->GetSubsystem(report->GetSourceID().mSubsystem)->GetComponent(report->GetSourceID())->mAuthorityLevel = (int)report->GetAuthorityCode();
                        if( discovery->GetVehicle(report->GetSourceID().mSubsystem).IsValid() && 
                            discovery->GetVehicle(report->GetSourceID().mSubsystem)->mAuthority < (int)report->GetAuthorityCode())
                        {
                            discovery->GetVehicle(report->GetSourceID().mSubsystem)->mAuthority = (int)report->GetAuthorityCode();
                        }
                    }
                }
                catch(Exception& e)
                {
                    e.Print();
                }
            }
        }
        break;
    case REPORT_CONTROL:
        // Not used.
        break;
    case REPORT_TIMEOUT:
        {
            const ReportTimeout* report = dynamic_cast<const ReportTimeout*>(message);
            if(report == NULL)
                return;

            Mutex::ScopedLock lock(&mControlMutex);
            mTimeoutPeriods[message->GetSourceID()] = report->GetTimeoutSeconds();
            if(mTimeoutPeriods[message->GetSourceID()] == 0)
            {
                // We always want to check for control.
                mTimeoutPeriods[message->GetSourceID()] = 2;
            }
        }
        break;
    case REQUEST_CONTROL:
        {
            const RequestControl* command = dynamic_cast<const RequestControl*>(message);
            if(mShutdownServiceFlag || command == NULL)
                return;
            
            ConfirmControl response(message->GetSourceID(), GetComponentID());

            Mutex::ScopedLock lock(&mControlMutex);
            // If they have minimum authority and we are
            // not under control or component has greater authority than
            // the current controller, accept.
            if(mControllableFlag && 
               command->GetAuthorityCode() >= mAuthorityCode &&
               (mControllerID == command->GetSourceID() || mControllerID.IsValid() == false || command->GetAuthorityCode() > mControllerAuthorityCode))
            {
                bool controlAccepted = true;
                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)
                    {
                        controlAccepted = controlChild->RequestControl();
                        if(controlAccepted)
                        {
                            break;
                        }
                    }
                }
                // This check is needed in case any child
                // service (Management) is in an Emergency state
                // and cannot transition.
                if(controlAccepted == false)
                {
                    response.SetResponseCode(ConfirmControl::NotAvailable);
                }
                else
                {
                    response.SetResponseCode(ConfirmControl::ControlAccepted);
                    if(mControllerID != command->GetSourceID() && mControllerID.IsValid())
                    {
                        // Notify controller that they have lost control.
                        RejectControl reject(mControllerID, GetComponentID());
                        reject.SetResponseCode(RejectControl::ControlReleased);
                        Send(&reject);
                    }
                    mControllerID = message->GetSourceID();
                    mControllerAuthorityCode = command->GetAuthorityCode();
                    mControllerCheckTime.SetCurrentTime();
                    mControllerUpdateTime.SetCurrentTime();
                    if(mDebugMessagesFlag)
                    {
                        Mutex::ScopedLock plock(&mDebugMessagesMutex);
                        std::cout << "[" << GetServiceID().ToString() << "-" << mComponentID.ToString() 
                            << "] - Control Granted to " << message->GetSourceID().ToString() << " at " << Time::GetUtcTime().ToString() << "\n";
                    }
                }
            }
            else
            {    
                if(mControllableFlag == false)
                {
                    response.SetResponseCode(ConfirmControl::NotAvailable);
                }
                else
                {                    
                    response.SetResponseCode(ConfirmControl::InsufficientAuthority);
                }      
                if(mDebugMessagesFlag)
                {
                    Mutex::ScopedLock plock(&mDebugMessagesMutex);
                    std::cout << "[" << GetServiceID().ToString() << "-" << mComponentID.ToString() 
                              << "] - Control Rejected from " << message->GetSourceID().ToString() << " at " << Time::GetUtcTime().ToString() << "\n";
                }
            }
            Send(&response);
        }
        break;
    case SET_AUTHORITY:
        {
            const SetAuthority* command = dynamic_cast<const SetAuthority*>(message);
            if(command == NULL)
                return;
            
            Mutex::ScopedLock lock(&mControlMutex);
            mAuthorityCode = command->GetAuthorityCode();
            SignalEvent(REPORT_AUTHORITY);

            // Update Discovery Contents.
            try
            {
                Discovery* discovery = GetComponent()->DiscoveryService();
                if(discovery)
                {
                    discovery->GetSubsystem(command->GetDestinationID().mSubsystem)->GetComponent(command->GetDestinationID())->mAuthorityLevel = (int)command->GetAuthorityCode();
                    if(discovery->GetVehicle(command->GetDestinationID().mSubsystem)->mAuthority < (int)command->GetAuthorityCode())
                    {
                        discovery->GetVehicle(command->GetDestinationID().mSubsystem)->mAuthority = (int)command->GetAuthorityCode();
                    }
                }
            }
            catch(Exception& e)
            {
                e.Print();
            }
        }
        break;
    default:
        break;
    };
}
////////////////////////////////////////////////////////////////////////////////////
///
///   \brief Method to request exclusive control of a component.
///
///   \param[in] id The ID of the component to request control of.
///   \param[in] reacquire If true, and control is lost for any reason, then
///                        we will try to re-acquire control.  If false, and
///                        control is lost, we forget about the component.
///   \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::RequestComponentControl(const Address& id, 
                                            const bool reacquire,
                                            const unsigned int waitTimeMs)
{
    RequestControl request(id, GetComponentID());
    request.SetAuthorityCode(mAuthorityCode);
    Message::List responses;
    ConfirmControl confirm;
    RejectControl reject;
    responses.push_back(&confirm);
    responses.push_back(&reject);

    if(Send(&request, responses, waitTimeMs) && responses.size() == 1)
    {
        // See if control was acquired.
        if(responses.front()->GetMessageCode() == CONFIRM_CONTROL)
        {
            if(confirm.GetResponseCode() == ConfirmControl::ControlAccepted)
            {
                // Don't use a scoped lock because we
                // dont' want the callback mutex run within it.

                mControlMutex.Lock();
                mControlledComponents.insert(id);
                mMaintainFlags[id] = reacquire;    
                mControlFlags[id] = true;
                // Set the time we verified we have control.
                mControlCheckTimes[id].SetCurrentTime();
                // Set the time we confirmed control.
                mControlConfirmTimes[id].SetCurrentTime();
                // Set a default value for timeout.
                mTimeoutPeriods[id] = mTimeoutPeriod;

                // Unlock
                mControlMutex.Unlock();

                // Query the timout period for the component.
                QueryTimeout query(id, GetComponentID());
                Send(&query);

                // Trigger acquisition of control events!

                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->ProcessAcquisitionOfControl(id);
                    }
                }

                Mutex::ScopedLock cbLock(&mCallbacksMutex);
                Callback::Set::iterator cb;
                for(cb = mCallbacks.begin();
                    cb != mCallbacks.end();
                    cb++)
                {
                    (*cb)->ProcessAcquisitionfControl(id);
                }

                return true;
            }
        }
        else
        {
            return false;
        }
    }
    return false;
}
Exemple #3
0
////////////////////////////////////////////////////////////////////////////////////
///
///   \brief Processes message received by the Service.  If not supported, then
///          message is passed to inheriting services depending on what
///          type of control has been established for the component.
///
///   This Service supports AccessControl related messages only.
///
///   \param[in] message Message data to process.
///
////////////////////////////////////////////////////////////////////////////////////
void AccessControl::Receive(const Message* message)
{
    if(AcceptCommandMessage(message) == false)
    {
        return;
    }

    if(mControllerID == message->GetSourceID())
    {
        mControllerUpdateTime.SetCurrentTime();
    }

    switch(message->GetMessageCode())
    {
    case CONFIRM_CONTROL:
        {
            const ConfirmControl* command = static_cast<const ConfirmControl*>(message);
            if(command == NULL)
                return;
            
            if(command->GetResponseCode() == ConfirmControl::ControlAccepted)
            {
                bool firstTime = true;

                    // Lock data.
                {
                    WriteLock wLock(mControlMutex);

                    // See if we already had control, and if not, then
                    // we re-acquired control of this component and must
                    // signal via callbacks, etc. of this event.
                    Address::Set::iterator controlledComponent = mControlledComponents.find(message->GetSourceID());
                    if(controlledComponent != mControlledComponents.end())
                    {
                        // If we get here, we have been trying to control this
                        // component. Check the control status flag.
                        std::map<Address, bool>::iterator flag = mControlFlags.find(message->GetSourceID());
                        if(flag->second == true)
                        {
                            // We already had control, nothing new here.
                            // So don't trigger events.
                            firstTime = false;
                        }
                    }

                    mControlledComponents.insert(message->GetSourceID());
                    mControlConfirmTimes[message->GetSourceID()].SetCurrentTime();
                    mControlFlags[message->GetSourceID()] = true;

                }
                if(DebugMessagesEnabled())
                {
                    if(firstTime)
                    {
                        std::stringstream dMessage;
                        dMessage << "[" << GetServiceID().ToString() << "-" << mComponentID.ToString() 
                                    << "] - Acquired Control of " << message->GetSourceID().ToString() << " at " << Time::GetUtcTime().ToString();
                        PrintDebugMessage(dMessage.str());
                    }
                    else
                    {
                        std::stringstream dMessage;
                        dMessage << "[" << GetServiceID().ToString() << "-" << mComponentID.ToString() 
                                    << "] - Maintained Control of " << message->GetSourceID().ToString() << " at " << Time::GetUtcTime().ToString();
                        PrintDebugMessage(dMessage.str());
                    }
                }

                // Trigger callbacks if needed.
                if(firstTime)
                {
                    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->ProcessAcquisitionOfControl(message->GetSourceID());
                        }
                    }
                    {
                        ReadLock cbrLock(mCallbacksMutex);
                        Callback::Set::iterator cb;
                        for(cb = mCallbacks.begin();
                            cb != mCallbacks.end();
                            cb++)
                        {
                            (*cb)->ProcessAcquisitionfControl(message->GetSourceID());
                        }
                    }
                }
            }
            else
            {
                Address::Set::iterator component;

                // Lock data.
                WriteLock wLock(mControlMutex);

                component = mControlledComponents.find(message->GetSourceID());
                if(component != mControlledComponents.end())
                {                    
                    std::map<Address, bool>::iterator flag;
                    flag = mMaintainFlags.find(message->GetSourceID());
                    if(flag != mMaintainFlags.end())
                    {
                        // If we didn't get control, and we are not
                        // trying to maintain control, remove the component
                        // from our lists. If we don't have high enough authority
                        // then don't bother trying to re-acquire control.
                        if(flag->second == false || command->GetMessageCode() == ConfirmControl::InsufficientAuthority)
                        {
                            EraseComponentControlInfo(message->GetSourceID());
                        }
                        else // Update control status
                        {
                            mControlFlags[message->GetSourceID()] = false;
                        }
                    }
                    // Delete junk data.
                    else
                    {
                        EraseComponentControlInfo(message->GetSourceID());
                    }
                }
            }
        }
        break;
    case QUERY_AUTHORITY:
        {
            if(mShutdownServiceFlag)
            {
                break;
            }
            
            ReportAuthority report(message->GetSourceID(), GetComponentID());
            {
                ReadLock rLock(mControlMutex);
                report.SetAuthorityCode(mAuthorityCode);
            }
            Send(&report);
        }
        break;
    case QUERY_CONTROL:
        {
            ReportControl report(message->GetSourceID(), GetComponentID());
            {
                ReadLock rLock(mControlMutex);
                report.SetAuthorityCode(mAuthorityCode);
                report.SetControllingComponent(mControllerID);
            }
            Send(&report);
        } 
        break;
    case QUERY_TIMEOUT:
        {
            ReportTimeout report(message->GetSourceID(), GetComponentID());
            {
                ReadLock rLock(mControlMutex);
                report.SetTimeoutSeconds(mTimeoutPeriod);
            }
            Send(&report);
        }
        break;
    case REJECT_CONTROL:
        {
            const RejectControl* command = static_cast<const RejectControl*>(message);
            if(mShutdownServiceFlag || command == NULL)
                return;

            bool signalCallbacks = false;
            {
                WriteLock wLock(mControlMutex);
                // Update state of controlled components.
                Address::Set::iterator component;
                component = mControlledComponents.find(message->GetSourceID());
                if(component != mControlledComponents.end())
                {                
                    std::map<Address, bool>::iterator flag;
                    flag = mMaintainFlags.find(message->GetSourceID());
                    if(flag != mMaintainFlags.end())
                    {
                        // If we lost control, and we are not
                        // trying to maintain control, remove the component
                        // from our lists.
                        if(flag->second == false)
                        {
                            mMaintainFlags.erase(flag);
                            mControlFlags.erase(mControlFlags.find(message->GetSourceID()));
                            mControlConfirmTimes.erase(mControlConfirmTimes.find(message->GetSourceID()));
                            mControlledComponents.erase(component);
                        }
                        else // Update control status
                        {
                            mControlFlags[message->GetSourceID()] = false;
                        }
                        signalCallbacks = true;
                    }
                    // Delete junk data.
                    else
                    {
                        if(mControlFlags.find(*component) != mControlFlags.end())
                        {
                            mControlFlags.erase(*component);
                        }
                        mControlledComponents.erase(*component);
                    }
                }
            }
            if(signalCallbacks)
            {
                // Generate events and callbacks.
                ReadLock cbrLock(mCallbacksMutex);
                Callback::Set::iterator cb;
                for(cb = mCallbacks.begin();
                    cb != mCallbacks.end();
                    cb++)
                {
                    (*cb)->ProcessLossOfControl(message->GetSourceID());
                }
            }
            
            if(DebugMessagesEnabled())
            {
                std::stringstream dMessage;
                dMessage << "[" << GetServiceID().ToString() << "-" << mComponentID.ToString() 
                          << "] - Lost Control of " << message->GetSourceID().ToString() << " at " << Time::GetUtcTime().ToString();
                PrintDebugMessage(dMessage.str());
            }
        }
        break;
    case RELEASE_CONTROL:
        {
            const ReleaseControl* command = static_cast<const ReleaseControl*>(message);
            if(mShutdownServiceFlag || command == NULL)
                return;

            if(command->GetSourceID() == mControllerID)
            {
                RejectControl response(mControllerID, GetComponentID());

                bool controlReleased = true;
                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)
                    {
                        if(controlChild->ReleaseControl())
                        {
                            controlReleased;
                        }
                    }
                }
                if(controlReleased)
                {
                    response.SetResponseCode(RejectControl::ControlReleased);
                    Send(&response);

                    // Update data members of who was in control to nobody!
                    {
                        WriteLock wLock(mControlMutex);
                        mControllerID = Address();
                        mControllerAuthorityCode = 0;
                        mControllerUpdateTime.Clear();
                        mControllerCheckTime.Clear();
                    }
                    if(DebugMessagesEnabled())
                    {
                        std::stringstream dMessage;
                        dMessage << "[" << GetServiceID().ToString() << "-" << mComponentID.ToString() 
                                 << "] - Control Released from " << message->GetSourceID().ToString() << " at " << Time::GetUtcTime().ToString();
                        PrintDebugMessage(dMessage.str());
                    }

                    // Signal a change in control event
                    SignalEvent(REPORT_CONTROL);

                    // Notify children of control release.
                    {
                        // Generate events and callbacks.
                        ReadLock cbrLock(mCallbacksMutex);
                        Callback::Set::iterator cb;
                        for(cb = mCallbacks.begin();
                            cb != mCallbacks.end();
                            cb++)
                        {
                            (*cb)->ProcessReleaseOfControl(message->GetSourceID());
                        }
                    }
                }
                else
                {
                    response.SetResponseCode(RejectControl::NotAvailable);
                    Send(&response);
                }
            }
        }
        break;
    case REPORT_AUTHORITY:
        {
            const JAUS::ReportAuthority* report = static_cast<const JAUS::ReportAuthority*>(message);
            if(report)
            {
                // Used by Discovery service to keep track of information
                // about components on the netework
            }
        }
        break;
    case REPORT_CONTROL:
        // Not used.
        break;
    case REPORT_TIMEOUT:
        {
            const ReportTimeout* report = static_cast<const ReportTimeout*>(message);
            if(report == NULL)
                return;

            WriteLock wLock(mControlMutex);
            mTimeoutPeriods[message->GetSourceID()] = report->GetTimeoutSeconds();
            if(mTimeoutPeriods[message->GetSourceID()] == 0)
            {
                // We always want to check for control.
                mTimeoutPeriods[message->GetSourceID()] = 2;
            }
        }
        break;
    case REQUEST_CONTROL:
        {
            const RequestControl* command = static_cast<const RequestControl*>(message);
            if(mShutdownServiceFlag || command == NULL)
                return;
            
            ConfirmControl response(message->GetSourceID(), GetComponentID());
#ifdef JAUS_USE_UPGRADE_LOCKS
            UpgradeLock upLock(mControlMutex);
#else
            WriteLock wLock(mControlMutex);
#endif
            // If they have minimum authority and we are
            // not under control or component has greater authority than
            // the current controller, accept.
            if(mControllableFlag && 
               command->GetAuthorityCode() >= mAuthorityCode &&
               (mControllerID == command->GetSourceID() || mControllerID.IsValid() == false || command->GetAuthorityCode() > mControllerAuthorityCode))
            {
                bool controlAccepted = true;
                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)
                    {
                        controlAccepted = controlChild->RequestControl();
                        if(controlAccepted)
                        {
                            break;
                        }
                    }
                }
                // This check is needed in case any child
                // service (Management) is in an Emergency state
                // and cannot transition.
                if(controlAccepted == false)
                {
                    response.SetResponseCode(ConfirmControl::NotAvailable);
                }
                else
                {
                    response.SetResponseCode(ConfirmControl::ControlAccepted);
                    if(mControllerID != command->GetSourceID() && mControllerID.IsValid())
                    {
                        // Notify controller that they have lost control.
                        RejectControl reject(mControllerID, GetComponentID());
                        reject.SetResponseCode(RejectControl::ControlReleased);
                        Send(&reject);
                    }
                    {
#ifdef JAUS_USE_UPGRADE_LOCKS
                        UpgradeToUniqueLock uniqueLock(upLock);
#endif
                        mControllerID = message->GetSourceID();
                        mControllerAuthorityCode = command->GetAuthorityCode();
                        mControllerCheckTime.SetCurrentTime();
                        mControllerUpdateTime.SetCurrentTime();
                    }
                    if(DebugMessagesEnabled())
                    {
                        std::stringstream dMessage;
                        dMessage << "[" << GetServiceID().ToString() << "-" << mComponentID.ToString() 
                                 << "] - Control Granted to " << message->GetSourceID().ToString() << " at " << Time::GetUtcTime().ToString();
                        PrintDebugMessage(dMessage.str());
                    }
                }
            }
            else
            {    
                if(mControllableFlag == false)
                {
                    response.SetResponseCode(ConfirmControl::NotAvailable);
                }
                else
                {                    
                    response.SetResponseCode(ConfirmControl::InsufficientAuthority);
                }
                if(DebugMessagesEnabled())
                {
                    std::stringstream dMessage;
                    dMessage << "[" << GetServiceID().ToString() << "-" << mComponentID.ToString() 
                        << "] - Control Rejected from " << message->GetSourceID().ToString() << " at " << Time::GetUtcTime().ToString();
                    PrintDebugMessage(dMessage.str());
                }
            }
            Send(&response);
        }
        break;
    case SET_AUTHORITY:
        {
            const SetAuthority* command = static_cast<const SetAuthority*>(message);
            if(command == NULL)
                return;
            
            SetAuthorityCode(command->GetAuthorityCode());
        }
        break;
    default:
        break;
    };
}
////////////////////////////////////////////////////////////////////////////////////
///
///   \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;

    mControlMutex.Lock();

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

    Address::Set::iterator component;
    Time currentTime;
    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.
                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;
            // Generate events and callbacks.
            Mutex::ScopedLock clock(&mCallbacksMutex);
            Callback::Set::iterator cb;
            for(cb = mCallbacks.begin();
                cb != mCallbacks.end();
                cb++)
            {
                (*cb)->ProcessLossOfControl(*component);
            }
        }
    }
    
    mControlMutex.Unlock();
    // Allow control check time to update.
    mControlMutex.Lock();

    Address controller = mControllerID;
    bool timeout = false;
    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(mDebugMessagesFlag)
        {
            Mutex::ScopedLock plock(&mDebugMessagesMutex);
            std::cout << "[" << GetServiceID().ToString() << "-" << mComponentID.ToString() 
                      << "] - Control Time Out From " << controller.ToString() << " at " << Time::GetUtcTime().ToString() << "\n";
        }
        // Clear values.
        mControllerID.Clear();
        mControllerAuthorityCode = 0;
        mControllerCheckTime.Clear();
        mControllerUpdateTime.Clear();
    }

    mControlMutex.Unlock();

    if(timeout)
    {
        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);
    }
}
Exemple #5
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);
    }
}