Line data Source code
1 : /* 2 : * 3 : * Copyright (c) 2021 Project CHIP Authors 4 : * 5 : * Licensed under the Apache License, Version 2.0 (the "License"); 6 : * you may not use this file except in compliance with the License. 7 : * You may obtain a copy of the License at 8 : * 9 : * http://www.apache.org/licenses/LICENSE-2.0 10 : * 11 : * Unless required by applicable law or agreed to in writing, software 12 : * distributed under the License is distributed on an "AS IS" BASIS, 13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 : * See the License for the specific language governing permissions and 15 : * limitations under the License. 16 : */ 17 : #pragma once 18 : 19 : #include "UDCClientState.h" 20 : #include <lib/core/CHIPError.h> 21 : #include <lib/support/CodeUtils.h> 22 : #include <system/TimeSource.h> 23 : 24 : namespace chip { 25 : namespace Protocols { 26 : namespace UserDirectedCommissioning { 27 : 28 : // UDC client state times out after 1 hour. This may need to be tweaked. 29 : inline constexpr const System::Clock::Timestamp kUDCClientTimeout = System::Clock::Milliseconds64(60 * 60 * 1000); 30 : 31 : /** 32 : * Handles a set of UDC Client Processing States. 33 : * 34 : * Intended for: 35 : * - ignoring/dropping duplicate UDC messages for the same instance 36 : * - tracking state of UDC work flow (see UDCClientProcessingState) 37 : * - timing out failed/declined UDC Clients 38 : */ 39 : template <size_t kMaxClientCount, Time::Source kTimeSource = Time::Source::kSystem> 40 : class UDCClients 41 : { 42 : public: 43 : /** 44 : * Allocates a new UDC client state object out of the internal resource pool. 45 : * 46 : * @param instanceName represents the UDS Client instance name 47 : * @param state [out] will contain the UDC Client state if one was available. May be null if no return value is desired. 48 : * 49 : * @note the newly created state will have an 'expiration' time set based on the current time source. 50 : * 51 : * @returns CHIP_NO_ERROR if state could be initialized. May fail if maximum UDC Client count 52 : * has been reached (with CHIP_ERROR_NO_MEMORY). 53 : */ 54 : CHECK_RETURN_VALUE 55 3 : CHIP_ERROR CreateNewUDCClientState(const char * instanceName, UDCClientState ** state) 56 : { 57 3 : const System::Clock::Timestamp currentTime = mTimeSource.GetMonotonicTimestamp(); 58 : 59 3 : CHIP_ERROR err = CHIP_ERROR_NO_MEMORY; 60 : 61 3 : if (state) 62 : { 63 3 : *state = nullptr; 64 : } 65 : 66 4 : for (auto & stateiter : mStates) 67 : { 68 4 : if (!stateiter.IsInitialized(currentTime)) 69 : { 70 3 : stateiter.SetInstanceName(instanceName); 71 3 : stateiter.SetExpirationTime(currentTime + kUDCClientTimeout); 72 3 : stateiter.SetUDCClientProcessingState(UDCClientProcessingState::kDiscoveringNode); 73 : 74 3 : if (state) 75 : { 76 3 : *state = &stateiter; 77 : } 78 : 79 3 : err = CHIP_NO_ERROR; 80 3 : break; 81 : } 82 : } 83 : 84 3 : return err; 85 : } 86 : 87 : /** 88 : * Get a UDC Client state given a Peer address. 89 : * 90 : * @param index is the index of the connection to find 91 : * 92 : * @return the state found, nullptr if not found 93 : */ 94 : CHECK_RETURN_VALUE 95 0 : UDCClientState * GetUDCClientState(size_t index) 96 : { 97 0 : if (index >= kMaxClientCount) 98 : { 99 0 : return nullptr; 100 : } 101 : 102 0 : const System::Clock::Timestamp currentTime = mTimeSource.GetMonotonicTimestamp(); 103 0 : UDCClientState state = mStates[index]; 104 0 : if (!state.IsInitialized(currentTime)) 105 : { 106 0 : return nullptr; 107 : } 108 0 : return &mStates[index]; 109 : } 110 : 111 : /** 112 : * Get a UDC Client state given a Peer address. 113 : * 114 : * @param address is the connection to find (based on address) 115 : * 116 : * @return the state found, nullptr if not found 117 : */ 118 : CHECK_RETURN_VALUE 119 : UDCClientState * FindUDCClientState(const PeerAddress & address) 120 : { 121 : const System::Clock::Timestamp currentTime = mTimeSource.GetMonotonicTimestamp(); 122 : 123 : UDCClientState * state = nullptr; 124 : 125 : for (auto & stateiter : mStates) 126 : { 127 : if (!stateiter.IsInitialized(currentTime)) 128 : { 129 : continue; 130 : } 131 : if (stateiter.GetPeerAddress() == address) 132 : { 133 : state = &stateiter; 134 : break; 135 : } 136 : } 137 : return state; 138 : } 139 : 140 : /** 141 : * Get a UDC Client state given an instance name. 142 : * 143 : * @param instanceName is the instance name to find (based upon instance name) 144 : * 145 : * @return the state found, nullptr if not found 146 : */ 147 : CHECK_RETURN_VALUE 148 0 : UDCClientState * FindUDCClientState(const char * instanceName) 149 : { 150 0 : const System::Clock::Timestamp currentTime = mTimeSource.GetMonotonicTimestamp(); 151 : 152 0 : UDCClientState * state = nullptr; 153 : 154 0 : for (auto & stateiter : mStates) 155 : { 156 0 : if (!stateiter.IsInitialized(currentTime)) 157 : { 158 0 : continue; 159 : } 160 : 161 : // TODO: check length of instanceName 162 0 : if (strncmp(stateiter.GetInstanceName(), instanceName, Dnssd::Commission::kInstanceNameMaxLength + 1) == 0) 163 : { 164 0 : state = &stateiter; 165 0 : break; 166 : } 167 : } 168 0 : return state; 169 : } 170 : 171 : // Reset all states to kNotInitialized 172 : void ResetUDCClientStates() 173 : { 174 : for (auto & stateiter : mStates) 175 : { 176 : stateiter.Reset(); 177 : } 178 : } 179 : 180 : /// Convenience method to mark a UDC Client state as active (non-expired) 181 6 : void MarkUDCClientActive(UDCClientState * state) 182 : { 183 6 : state->SetExpirationTime(mTimeSource.GetMonotonicTimestamp() + kUDCClientTimeout); 184 6 : } 185 : 186 : private: 187 : Time::TimeSource<kTimeSource> mTimeSource; 188 : UDCClientState mStates[kMaxClientCount]; 189 : }; 190 : 191 : } // namespace UserDirectedCommissioning 192 : } // namespace Protocols 193 : } // namespace chip