| /* |
| * |
| * 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 <lib/core/CHIPError.h> |
| #include <lib/support/CodeUtils.h> |
| #include <system/TimeSource.h> |
| |
| namespace chip { |
| namespace Protocols { |
| namespace UserDirectedCommissioning { |
| |
| // UDC client state times out after 1 hour. This may need to be tweaked. |
| 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 <size_t kMaxClientCount, Time::Source kTimeSource = Time::Source::kSystem> |
| 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<kTimeSource> mTimeSource; |
| UDCClientState mStates[kMaxClientCount]; |
| }; |
| |
| } // namespace UserDirectedCommissioning |
| } // namespace Protocols |
| } // namespace chip |