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
|