//////////////////////////////////////////////////////////////////////////////////// /// /// \brief Creates a multicast listening socket to try and discover /// subsystems on the network for dynamic selection of a component /// ID. /// /// \param[in] discovered List of discovered components performing Discovery. /// \param[in] waitTimeMs How long to listen for. /// \param[in] multicastGroup Multicast group to listen on. /// /// \return True if was able to listen, false on failure to listen. /// //////////////////////////////////////////////////////////////////////////////////// bool JUDP::ListenForSubsystems(Address::Set& discovered, const unsigned int waitTimeMs, const CxUtils::IP4Address& multicastGroup) { discovered.clear(); CxUtils::UdpSharedServer listen; if(listen.InitializeSocket(JUDP::Port, multicastGroup)) { Packet packet; Header header; UShort messageCode; CxUtils::IP4Address ip; Time::Stamp start = Time::GetUtcTimeMs(); while(Time::GetUtcTimeMs() - start < waitTimeMs) { if(listen.Recv(packet, ip)) { packet.SetReadPos(1); if(header.Read(packet) && packet.Read(messageCode)) { discovered.insert(header.mSourceID); } } } return true; } return false; }
//////////////////////////////////////////////////////////////////////////////////// /// /// \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; }
//////////////////////////////////////////////////////////////////////////////////// /// /// \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); } }