/* * * Copyright (c) 2021 Project CHIP Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "UDCClientState.h" #include #include #include namespace chip { namespace Protocols { namespace UserDirectedCommissioning { // UDC client state times out after 1 hour. This may need to be tweaked. inline constexpr const System::Clock::Timestamp kUDCClientTimeout = System::Clock::Milliseconds64(60 * 60 * 1000); /** * Handles a set of UDC Client Processing States. * * Intended for: * - ignoring/dropping duplicate UDC messages for the same instance * - tracking state of UDC work flow (see UDCClientProcessingState) * - timing out failed/declined UDC Clients */ template class UDCClients { public: /** * Allocates a new UDC client state object out of the internal resource pool. * * @param instanceName represents the UDS Client instance name * @param state [out] will contain the UDC Client state if one was available. May be null if no return value is desired. * * @note the newly created state will have an 'expiration' time set based on the current time source. * * @returns CHIP_NO_ERROR if state could be initialized. May fail if maximum UDC Client count * has been reached (with CHIP_ERROR_NO_MEMORY). */ CHECK_RETURN_VALUE CHIP_ERROR CreateNewUDCClientState(const char * instanceName, UDCClientState ** state) { const System::Clock::Timestamp currentTime = mTimeSource.GetMonotonicTimestamp(); CHIP_ERROR err = CHIP_ERROR_NO_MEMORY; if (state) { *state = nullptr; } for (auto & stateiter : mStates) { if (!stateiter.IsInitialized(currentTime)) { stateiter.SetInstanceName(instanceName); stateiter.SetExpirationTime(currentTime + kUDCClientTimeout); stateiter.SetUDCClientProcessingState(UDCClientProcessingState::kDiscoveringNode); if (state) { *state = &stateiter; } err = CHIP_NO_ERROR; break; } } return err; } /** * Get a UDC Client state given a Peer address. * * @param index is the index of the connection to find * * @return the state found, nullptr if not found */ CHECK_RETURN_VALUE UDCClientState * GetUDCClientState(size_t index) { if (index >= kMaxClientCount) { return nullptr; } const System::Clock::Timestamp currentTime = mTimeSource.GetMonotonicTimestamp(); UDCClientState state = mStates[index]; if (!state.IsInitialized(currentTime)) { return nullptr; } return &mStates[index]; } /** * Get a UDC Client state given a Peer address. * * @param address is the connection to find (based on address) * * @return the state found, nullptr if not found */ CHECK_RETURN_VALUE UDCClientState * FindUDCClientState(const PeerAddress & address) { const System::Clock::Timestamp currentTime = mTimeSource.GetMonotonicTimestamp(); UDCClientState * state = nullptr; for (auto & stateiter : mStates) { if (!stateiter.IsInitialized(currentTime)) { continue; } if (stateiter.GetPeerAddress() == address) { state = &stateiter; break; } } return state; } /** * Get a UDC Client state given an instance name. * * @param instanceName is the instance name to find (based upon instance name) * * @return the state found, nullptr if not found */ CHECK_RETURN_VALUE UDCClientState * FindUDCClientState(const char * instanceName) { const System::Clock::Timestamp currentTime = mTimeSource.GetMonotonicTimestamp(); UDCClientState * state = nullptr; for (auto & stateiter : mStates) { if (!stateiter.IsInitialized(currentTime)) { continue; } // TODO: check length of instanceName if (strncmp(stateiter.GetInstanceName(), instanceName, Dnssd::Commission::kInstanceNameMaxLength + 1) == 0) { state = &stateiter; break; } } return state; } // Reset all states to kNotInitialized void ResetUDCClientStates() { for (auto & stateiter : mStates) { stateiter.Reset(); } } /// Convenience method to mark a UDC Client state as active (non-expired) void MarkUDCClientActive(UDCClientState * state) { state->SetExpirationTime(mTimeSource.GetMonotonicTimestamp() + kUDCClientTimeout); } private: Time::TimeSource mTimeSource; UDCClientState mStates[kMaxClientCount]; }; } // namespace UserDirectedCommissioning } // namespace Protocols } // namespace chip