3 * Copyright (c) 2020 Project CHIP Authors
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <core/CHIPError.h>
20 #include <support/CodeUtils.h>
21 #include <system/TimeSource.h>
22 #include <transport/AdminPairingTable.h>
23 #include <transport/PeerConnectionState.h>
28 // TODO; use 0xffff to match any key id, this is a temporary solution for
29 // InteractionModel, where key id is not obtainable. This will be removed when
30 // InteractionModel is migrated to messaging layer
31 constexpr const uint16_t kAnyKeyId = 0xffff;
34 * Handles a set of peer connection states.
37 * - handle connection active time and expiration
38 * - allocate and free space for connection states.
40 template <size_t kMaxConnectionCount, Time::Source kTimeSource = Time::Source::kSystem>
45 * Allocates a new peer connection state state object out of the internal resource pool.
47 * @param address represents the connection state address
48 * @param state [out] will contain the connection state if one was available. May be null if no return value is desired.
50 * @note the newly created state will have an 'active' time set based on the current time source.
52 * @returns CHIP_NO_ERROR if state could be initialized. May fail if maximum connection count
53 * has been reached (with CHIP_ERROR_NO_MEMORY).
56 CHIP_ERROR CreateNewPeerConnectionState(const PeerAddress & address, PeerConnectionState ** state)
58 CHIP_ERROR err = CHIP_ERROR_NO_MEMORY;
65 for (size_t i = 0; i < kMaxConnectionCount; i++)
67 if (!mStates[i].IsInitialized())
69 mStates[i] = PeerConnectionState(address);
70 mStates[i].SetLastActivityTimeMs(mTimeSource.GetCurrentMonotonicTimeMs());
86 * Allocates a new peer connection state state object out of the internal resource pool.
88 * @param peerNode represents optional peer Node's ID
89 * @param peerKeyId represents the encryption key ID assigned by peer node
90 * @param localKeyId represents the encryption key ID assigned by local node
91 * @param state [out] will contain the connection state if one was available. May be null if no return value is desired.
93 * @note the newly created state will have an 'active' time set based on the current time source.
95 * @returns CHIP_NO_ERROR if state could be initialized. May fail if maximum connection count
96 * has been reached (with CHIP_ERROR_NO_MEMORY).
99 CHIP_ERROR CreateNewPeerConnectionState(const Optional<NodeId> & peerNode, uint16_t peerKeyId, uint16_t localKeyId,
100 PeerConnectionState ** state)
102 CHIP_ERROR err = CHIP_ERROR_NO_MEMORY;
109 for (size_t i = 0; i < kMaxConnectionCount; i++)
111 if (!mStates[i].IsInitialized())
113 mStates[i] = PeerConnectionState();
114 mStates[i].SetPeerKeyID(peerKeyId);
115 mStates[i].SetLocalKeyID(localKeyId);
116 mStates[i].SetLastActivityTimeMs(mTimeSource.GetCurrentMonotonicTimeMs());
118 if (peerNode.ValueOr(kUndefinedNodeId) != kUndefinedNodeId)
120 mStates[i].SetPeerNodeId(peerNode.Value());
125 *state = &mStates[i];
137 * Get a peer connection state given a Peer address.
139 * @param address is the connection to find (based on address)
140 * @param begin If a member of the pool, will start search from the next item. Can be nullptr to search from start.
142 * @return the state found, nullptr if not found
145 PeerConnectionState * FindPeerConnectionState(const PeerAddress & address, PeerConnectionState * begin)
147 PeerConnectionState * state = nullptr;
148 PeerConnectionState * iter = &mStates[0];
150 if (begin >= iter && begin < &mStates[kMaxConnectionCount])
155 for (; iter < &mStates[kMaxConnectionCount]; iter++)
157 if (iter->GetPeerAddress() == address)
167 * Get a peer connection state given a Node Id.
169 * @param nodeId is the connection to find (based on nodeId). Note that initial connections
170 * do not have a node id set. Use this if you know the node id should be set.
171 * @param begin If a member of the pool, will start search from the next item. Can be nullptr to search from start.
173 * @return the state found, nullptr if not found
176 PeerConnectionState * FindPeerConnectionState(NodeId nodeId, PeerConnectionState * begin)
178 PeerConnectionState * state = nullptr;
179 PeerConnectionState * iter = &mStates[0];
181 if (begin >= iter && begin < &mStates[kMaxConnectionCount])
186 for (; iter < &mStates[kMaxConnectionCount]; iter++)
188 if (!iter->IsInitialized())
192 if (iter->GetPeerNodeId() == nodeId)
202 * Get a peer connection state given a Node Id and Peer's Encryption Key Id.
204 * @param nodeId is the connection to find (based on nodeId). Note that initial connections
205 * do not have a node id set. Use this if you know the node id should be set.
206 * @param peerKeyId Encryption key ID used by the peer node.
207 * @param begin If a member of the pool, will start search from the next item. Can be nullptr to search from start.
209 * @return the state found, nullptr if not found
212 PeerConnectionState * FindPeerConnectionState(Optional<NodeId> nodeId, uint16_t peerKeyId, PeerConnectionState * begin)
214 PeerConnectionState * state = nullptr;
215 PeerConnectionState * iter = &mStates[0];
217 if (begin >= iter && begin < &mStates[kMaxConnectionCount])
222 for (; iter < &mStates[kMaxConnectionCount]; iter++)
224 if (!iter->IsInitialized())
228 if (peerKeyId == kAnyKeyId || iter->GetPeerKeyID() == peerKeyId)
230 if (nodeId.ValueOr(kUndefinedNodeId) == kUndefinedNodeId || iter->GetPeerNodeId() == kUndefinedNodeId ||
231 iter->GetPeerNodeId() == nodeId.Value())
242 * Get a peer connection state given the local Encryption Key Id.
244 * @param keyId Encryption key ID assigned by the local node.
245 * @param begin If a member of the pool, will start search from the next item. Can be nullptr to search from start.
247 * @return the state found, nullptr if not found
250 PeerConnectionState * FindPeerConnectionState(uint16_t keyId, PeerConnectionState * begin)
252 PeerConnectionState * state = nullptr;
253 PeerConnectionState * iter = &mStates[0];
255 assert(begin == nullptr || (begin >= iter && begin < &mStates[kMaxConnectionCount]));
257 if (begin != nullptr)
262 for (; iter < &mStates[kMaxConnectionCount]; iter++)
264 if (!iter->IsInitialized())
269 if (iter->GetLocalKeyID() == keyId)
279 * Get a peer connection state given a Node Id and Peer's Encryption Key Id.
281 * @param nodeId is the connection to find (based on peer nodeId). Note that initial connections
282 * do not have a node id set. Use this if you know the node id should be set.
283 * @param localKeyId Encryption key ID used by the local node.
284 * @param begin If a member of the pool, will start search from the next item. Can be nullptr to search from start.
286 * @return the state found, nullptr if not found
289 PeerConnectionState * FindPeerConnectionStateByLocalKey(Optional<NodeId> nodeId, uint16_t localKeyId,
290 PeerConnectionState * begin)
292 PeerConnectionState * state = nullptr;
293 PeerConnectionState * iter = &mStates[0];
295 if (begin >= iter && begin < &mStates[kMaxConnectionCount])
300 for (; iter < &mStates[kMaxConnectionCount]; iter++)
302 if (!iter->IsInitialized())
306 if (iter->GetLocalKeyID() == localKeyId)
308 if (nodeId.ValueOr(kUndefinedNodeId) == kUndefinedNodeId || iter->GetPeerNodeId() == kUndefinedNodeId ||
309 iter->GetPeerNodeId() == nodeId.Value())
319 /// Convenience method to mark a peer connection state as active
320 void MarkConnectionActive(PeerConnectionState * state)
322 state->SetLastActivityTimeMs(mTimeSource.GetCurrentMonotonicTimeMs());
325 /// Convenience method to expired a peer connection state and fired the related callback
326 template <typename Callback>
327 void MarkConnectionExpired(PeerConnectionState * state, Callback callback)
330 *state = PeerConnectionState(PeerAddress::Uninitialized());
334 * Iterates through all active connections and expires any connection with an idle time
335 * larger than the given amount.
337 * Expiring a connection involves callback execution and then clearing the internal state.
339 template <typename Callback>
340 void ExpireInactiveConnections(uint64_t maxIdleTimeMs, Callback callback)
342 const uint64_t currentTime = mTimeSource.GetCurrentMonotonicTimeMs();
344 for (size_t i = 0; i < kMaxConnectionCount; i++)
346 if (!mStates[i].GetPeerAddress().IsInitialized())
348 continue; // not an active connection
351 uint64_t connectionActiveTime = mStates[i].GetLastActivityTimeMs();
352 if (connectionActiveTime + maxIdleTimeMs >= currentTime)
354 continue; // not expired
357 MarkConnectionExpired(&mStates[i], callback);
361 /// Allows access to the underlying time source used for keeping track of connection active time
362 Time::TimeSource<kTimeSource> & GetTimeSource() { return mTimeSource; }
365 Time::TimeSource<kTimeSource> mTimeSource;
366 PeerConnectionState mStates[kMaxConnectionCount];
369 } // namespace Transport