Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020 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 :
18 : /**
19 : * @file
20 : * Defines the CHIP ExchangeManager class and its supporting types
21 : * for Exchange management.
22 : *
23 : */
24 :
25 : #pragma once
26 :
27 : #include <array>
28 :
29 : #include <lib/support/DLLUtil.h>
30 : #include <lib/support/Pool.h>
31 : #include <lib/support/TypeTraits.h>
32 : #include <messaging/ExchangeContext.h>
33 : #include <messaging/ReliableMessageMgr.h>
34 : #include <protocols/Protocols.h>
35 : #include <transport/SessionManager.h>
36 :
37 : namespace chip {
38 : namespace Messaging {
39 :
40 : class ExchangeContext;
41 : class ExchangeDelegate;
42 : #if CONFIG_BUILD_FOR_HOST_UNIT_TEST
43 : class TestOnlyReceivedMessageObserver;
44 : #endif
45 :
46 : static constexpr int16_t kAnyMessageType = -1;
47 :
48 : /**
49 : * @brief
50 : * This class is used to manage ExchangeContexts with other CHIP nodes.
51 : * It works on be behalf of higher layers, creating ExchangeContexts and
52 : * handling the registration/unregistration of unsolicited message handlers.
53 : */
54 : class DLL_EXPORT ExchangeManager : public SessionMessageDelegate
55 : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
56 : ,
57 : public SessionConnectionDelegate
58 : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
59 : {
60 : friend class ExchangeContext;
61 :
62 : public:
63 : ExchangeManager();
64 : ExchangeManager(const ExchangeManager &) = delete;
65 : ExchangeManager operator=(const ExchangeManager &) = delete;
66 :
67 : /**
68 : * Initialize the ExchangeManager object. Within the lifetime
69 : * of this instance, this method is invoked once after object
70 : * construction until a call to Shutdown is made to terminate the
71 : * instance.
72 : *
73 : * @param[in] sessionManager A pointer to the SessionManager object.
74 : *
75 : * @retval #CHIP_ERROR_INCORRECT_STATE If the state is not equal to
76 : * kState_NotInitialized.
77 : * @retval #CHIP_NO_ERROR On success.
78 : *
79 : */
80 : CHIP_ERROR Init(SessionManager * sessionManager);
81 :
82 : /**
83 : * Shutdown the ExchangeManager. This terminates this instance
84 : * of the object and releases all held resources.
85 : *
86 : * Please see documentation for SessionManager::Shutdown() for ordering
87 : * dependecies between that and this Shutdown() method.
88 : *
89 : * @note
90 : * The protocol should only call this function after ensuring that
91 : * there are no active ExchangeContext objects (again, see
92 : * SessionManager::Shutdown() documentation). Furthermore, it is the
93 : * onus of the application to de-allocate the ExchangeManager
94 : * object after calling ExchangeManager::Shutdown().
95 : */
96 : void Shutdown();
97 :
98 : /**
99 : * Creates a new ExchangeContext with a given peer CHIP node specified by the peer node identifier.
100 : *
101 : * @param[in] session The identifier of the secure session (possibly
102 : * the empty session for a non-secure exchange)
103 : * for which the ExchangeContext is being set up.
104 : *
105 : * @param[in] delegate A pointer to ExchangeDelegate.
106 : * @param[in] isInitiator Set to true if the exchange is created on the initiator. This is generally true
107 : * except in unit tests.
108 : *
109 : * @return A pointer to the created ExchangeContext object On success. Otherwise NULL if no object
110 : * can be allocated or is available.
111 : */
112 : ExchangeContext * NewContext(const SessionHandle & session, ExchangeDelegate * delegate, bool isInitiator = true);
113 :
114 4788 : void ReleaseContext(ExchangeContext * ec) { mContextPool.ReleaseObject(ec); }
115 :
116 : /**
117 : * Register an unsolicited message handler for a given protocol identifier. This handler would be
118 : * invoked for all messages of the given protocol.
119 : *
120 : * @param[in] protocolId The protocol identifier of the received message.
121 : *
122 : * @param[in] handler A pointer to UnsolicitedMessageHandler.
123 : *
124 : * @retval #CHIP_ERROR_TOO_MANY_UNSOLICITED_MESSAGE_HANDLERS If the unsolicited message handler pool
125 : * is full and a new one cannot be allocated.
126 : * @retval #CHIP_NO_ERROR On success.
127 : */
128 : CHIP_ERROR RegisterUnsolicitedMessageHandlerForProtocol(Protocols::Id protocolId, UnsolicitedMessageHandler * handler);
129 :
130 : /**
131 : * Register an unsolicited message handler for a given protocol identifier and message type.
132 : *
133 : * @param[in] protocolId The protocol identifier of the received message.
134 : *
135 : * @param[in] msgType The message type of the corresponding protocol.
136 : *
137 : * @param[in] handler A pointer to UnsolicitedMessageHandler.
138 : *
139 : * @retval #CHIP_ERROR_TOO_MANY_UNSOLICITED_MESSAGE_HANDLERS If the unsolicited message handler pool
140 : * is full and a new one cannot be allocated.
141 : * @retval #CHIP_NO_ERROR On success.
142 : */
143 : CHIP_ERROR RegisterUnsolicitedMessageHandlerForType(Protocols::Id protocolId, uint8_t msgType,
144 : UnsolicitedMessageHandler * handler);
145 :
146 : /**
147 : * A strongly-message-typed version of RegisterUnsolicitedMessageHandlerForType.
148 : */
149 : template <typename MessageType, typename = std::enable_if_t<std::is_enum<MessageType>::value>>
150 508 : CHIP_ERROR RegisterUnsolicitedMessageHandlerForType(MessageType msgType, UnsolicitedMessageHandler * handler)
151 : {
152 508 : return RegisterUnsolicitedMessageHandlerForType(Protocols::MessageTypeTraits<MessageType>::ProtocolId(),
153 1016 : to_underlying(msgType), handler);
154 : }
155 :
156 : /**
157 : * Unregister an unsolicited message handler for a given protocol identifier.
158 : *
159 : * @param[in] protocolId The protocol identifier of the received message.
160 : *
161 : * @retval #CHIP_ERROR_NO_UNSOLICITED_MESSAGE_HANDLER If the matching unsolicited message handler
162 : * is not found.
163 : * @retval #CHIP_NO_ERROR On success.
164 : */
165 : CHIP_ERROR UnregisterUnsolicitedMessageHandlerForProtocol(Protocols::Id protocolId);
166 :
167 : /**
168 : * Unregister an unsolicited message handler for a given protocol identifier and message type.
169 : *
170 : * @param[in] protocolId The protocol identifier of the received message.
171 : *
172 : * @param[in] msgType The message type of the corresponding protocol.
173 : *
174 : * @param[out] outHandler If non-null, receives the handler that was unregistered. If no
175 : * handler matched, *outHandler is set to nullptr. Callers may pass
176 : * nullptr if they do not need this information.
177 : *
178 : * @retval #CHIP_ERROR_NO_UNSOLICITED_MESSAGE_HANDLER If the matching unsolicited message handler
179 : * is not found.
180 : * @retval #CHIP_NO_ERROR On success.
181 : */
182 : CHIP_ERROR UnregisterUnsolicitedMessageHandlerForType(Protocols::Id protocolId, uint8_t msgType,
183 : Messaging::UnsolicitedMessageHandler ** outHandler = nullptr);
184 :
185 : /**
186 : * A strongly-message-typed version of UnregisterUnsolicitedMessageHandlerForType.
187 : */
188 : template <typename MessageType, typename = std::enable_if_t<std::is_enum<MessageType>::value>>
189 492 : CHIP_ERROR UnregisterUnsolicitedMessageHandlerForType(MessageType msgType,
190 : Messaging::UnsolicitedMessageHandler ** outHandler = nullptr)
191 : {
192 492 : return UnregisterUnsolicitedMessageHandlerForType(Protocols::MessageTypeTraits<MessageType>::ProtocolId(),
193 984 : to_underlying(msgType), outHandler);
194 : }
195 :
196 : /**
197 : * A method to call Close() on all contexts that have a given delegate as
198 : * their delegate. To be used if the delegate is being destroyed. This
199 : * method will guarantee that it does not call into the delegate.
200 : */
201 : void CloseAllContextsForDelegate(const ExchangeDelegate * delegate);
202 :
203 40254 : SessionManager * GetSessionManager() const { return mSessionManager; }
204 :
205 53627 : ReliableMessageMgr * GetReliableMessageMgr() { return &mReliableMessageMgr; };
206 :
207 : FabricIndex GetFabricIndex() const { return mFabricIndex; }
208 :
209 : uint16_t GetNextKeyId() { return ++mNextKeyId; }
210 :
211 27560680 : size_t GetNumActiveExchanges() { return mContextPool.Allocated(); }
212 :
213 : #if CONFIG_BUILD_FOR_HOST_UNIT_TEST
214 : void SetTestOnlyReceivedMessageObserver(TestOnlyReceivedMessageObserver * observer) { mTestOnlyReceivedObserver = observer; }
215 : TestOnlyReceivedMessageObserver * GetTestOnlyReceivedMessageObserver() const { return mTestOnlyReceivedObserver; }
216 : #endif // CONFIG_BUILD_FOR_HOST_UNIT_TEST
217 :
218 : private:
219 : enum class State
220 : {
221 : kState_NotInitialized = 0, // Used to indicate that the ExchangeManager is not initialized.
222 : kState_Initialized = 1 // Used to indicate that the ExchangeManager is initialized.
223 : };
224 :
225 : struct UnsolicitedMessageHandlerSlot
226 : {
227 5336 : UnsolicitedMessageHandlerSlot() : ProtocolId(Protocols::NotSpecified) {}
228 :
229 4537 : constexpr void Reset() { Handler = nullptr; }
230 27236 : constexpr bool IsInUse() const { return Handler != nullptr; }
231 : // Matches() only returns a sensible value if IsInUse() is true.
232 2107 : constexpr bool Matches(Protocols::Id aProtocolId, int16_t aMessageType) const
233 : {
234 2107 : return ProtocolId == aProtocolId && MessageType == aMessageType;
235 : }
236 :
237 : Protocols::Id ProtocolId;
238 : // Message types are normally 8-bit unsigned ints, but we use
239 : // kAnyMessageType, which is negative, to represent a wildcard handler,
240 : // so need a type that can store both that and all valid message type
241 : // values.
242 : int16_t MessageType;
243 :
244 : UnsolicitedMessageHandler * Handler;
245 : };
246 :
247 : uint16_t mNextExchangeId;
248 : uint16_t mNextKeyId;
249 : State mState;
250 :
251 : FabricIndex mFabricIndex = 0;
252 :
253 : ObjectPool<ExchangeContext, CHIP_CONFIG_MAX_EXCHANGE_CONTEXTS> mContextPool;
254 :
255 : SessionManager * mSessionManager;
256 : ReliableMessageMgr mReliableMessageMgr;
257 :
258 : #if CONFIG_BUILD_FOR_HOST_UNIT_TEST
259 : TestOnlyReceivedMessageObserver * mTestOnlyReceivedObserver = nullptr;
260 : #endif // CONFIG_BUILD_FOR_HOST_UNIT_TEST
261 :
262 : UnsolicitedMessageHandlerSlot UMHandlerPool[CHIP_CONFIG_MAX_UNSOLICITED_MESSAGE_HANDLERS];
263 :
264 : CHIP_ERROR RegisterUMH(Protocols::Id protocolId, int16_t msgType, UnsolicitedMessageHandler * handler);
265 : CHIP_ERROR UnregisterUMH(Protocols::Id protocolId, int16_t msgType,
266 : Messaging::UnsolicitedMessageHandler ** outHandler = nullptr);
267 :
268 : void OnMessageReceived(const PacketHeader & packetHeader, const PayloadHeader & payloadHeader, const SessionHandle & session,
269 : DuplicateMessage isDuplicate, System::PacketBufferHandle && msgBuf) override;
270 : void SendStandaloneAckIfNeeded(const PacketHeader & packetHeader, const PayloadHeader & payloadHeader,
271 : const SessionHandle & session, MessageFlags msgFlags, System::PacketBufferHandle && msgBuf);
272 : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
273 : void OnTCPConnectionClosed(const Transport::ActiveTCPConnectionState & conn, const SessionHandle & session,
274 : CHIP_ERROR conErr) override;
275 : bool OnTCPConnectionAttemptComplete(Transport::ActiveTCPConnectionHandle & conn, CHIP_ERROR conErr) override;
276 : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
277 : };
278 :
279 : #if CONFIG_BUILD_FOR_HOST_UNIT_TEST
280 : /**
281 : * Test-only observer invoked for every inbound message on the ExchangeManager, just before dispatch.
282 : * Subclass and register an instance via ExchangeManager::SetTestOnlyReceivedMessageObserver to inspect inbound headers and message
283 : * bytes (e.g. to assert on Message/Exchange flags in Python integration tests).
284 : *
285 : * Lifetime: the ExchangeManager only holds a raw pointer to the observer and does not own it. The observer must outlive its
286 : * registration. The pointer is cleared on Init() and Shutdown(), so it does not survive a Shutdown()/re-Init() cycle; for any
287 : * other teardown the caller is responsible for unregistering (passing nullptr) before the observer is destroyed.
288 : *
289 : * OnMessageReceived must not consume or retain msgBuf beyond the call; call msgBuf.Retain() if a handle needs to outlive it.
290 : */
291 : class TestOnlyReceivedMessageObserver
292 : {
293 : public:
294 : virtual ~TestOnlyReceivedMessageObserver() = default;
295 :
296 : virtual void OnMessageReceived(const PacketHeader & packetHeader, const PayloadHeader & payloadHeader,
297 : const System::PacketBufferHandle & msgBuf) = 0;
298 : };
299 : #endif // CONFIG_BUILD_FOR_HOST_UNIT_TEST
300 :
301 : } // namespace Messaging
302 : } // namespace chip
|