Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / messaging / ExchangeMgr.cpp
1 /*
2  *
3  *    Copyright (c) 2020-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
18 /**
19  *    @file
20  *      This file implements the ExchangeManager class.
21  *
22  */
23
24 #ifndef __STDC_FORMAT_MACROS
25 #define __STDC_FORMAT_MACROS
26 #endif
27
28 #ifndef __STDC_LIMIT_MACROS
29 #define __STDC_LIMIT_MACROS
30 #endif
31
32 #include <cstring>
33 #include <inttypes.h>
34 #include <stddef.h>
35
36 #include <core/CHIPCore.h>
37 #include <core/CHIPEncoding.h>
38 #include <messaging/ExchangeContext.h>
39 #include <messaging/ExchangeMgr.h>
40 #include <protocols/Protocols.h>
41 #include <support/CHIPFaultInjection.h>
42 #include <support/CodeUtils.h>
43 #include <support/RandUtils.h>
44 #include <support/logging/CHIPLogging.h>
45
46 using namespace chip::Encoding;
47 using namespace chip::Inet;
48 using namespace chip::System;
49
50 namespace chip {
51 namespace Messaging {
52
53 /**
54  *  Constructor for the ExchangeManager class.
55  *  It sets the state to kState_NotInitialized.
56  *
57  *  @note
58  *    The class must be initialized via ExchangeManager::Init()
59  *    prior to use.
60  *
61  */
62 ExchangeManager::ExchangeManager() : mReliableMessageMgr(mContextPool)
63 {
64     mState = State::kState_NotInitialized;
65 }
66
67 CHIP_ERROR ExchangeManager::Init(SecureSessionMgr * sessionMgr)
68 {
69     CHIP_ERROR err = CHIP_NO_ERROR;
70
71     VerifyOrReturnError(mState == State::kState_NotInitialized, err = CHIP_ERROR_INCORRECT_STATE);
72
73     mSessionMgr = sessionMgr;
74
75     mNextExchangeId = GetRandU16();
76     mNextKeyId      = 0;
77
78     mContextsInUse = 0;
79
80     for (auto & handler : UMHandlerPool)
81     {
82         // Mark all handlers as unallocated.  This handles both initial
83         // initialization and the case when the consumer shuts us down and
84         // then re-initializes without removing registered handlers.
85         handler.Reset();
86     }
87
88     mSessionMgr->GetTransportManager()->SetRendezvousSession(this);
89
90     sessionMgr->SetDelegate(this);
91
92     mReliableMessageMgr.Init(sessionMgr->SystemLayer(), sessionMgr);
93
94     err = mMessageCounterSyncMgr.Init(this);
95     ReturnErrorOnFailure(err);
96
97     mState = State::kState_Initialized;
98
99     return err;
100 }
101
102 CHIP_ERROR ExchangeManager::Shutdown()
103 {
104     mMessageCounterSyncMgr.Shutdown();
105     mReliableMessageMgr.Shutdown();
106
107     if (mSessionMgr != nullptr)
108     {
109         mSessionMgr->SetDelegate(nullptr);
110         mSessionMgr = nullptr;
111     }
112
113     mState = State::kState_NotInitialized;
114
115     return CHIP_NO_ERROR;
116 }
117
118 ExchangeContext * ExchangeManager::NewContext(SecureSessionHandle session, ExchangeDelegate * delegate)
119 {
120     return AllocContext(mNextExchangeId++, session, true, delegate);
121 }
122
123 CHIP_ERROR ExchangeManager::RegisterUnsolicitedMessageHandlerForProtocol(Protocols::Id protocolId, ExchangeDelegate * delegate)
124 {
125     return RegisterUMH(protocolId, kAnyMessageType, delegate);
126 }
127
128 CHIP_ERROR ExchangeManager::RegisterUnsolicitedMessageHandlerForType(Protocols::Id protocolId, uint8_t msgType,
129                                                                      ExchangeDelegate * delegate)
130 {
131     return RegisterUMH(protocolId, static_cast<int16_t>(msgType), delegate);
132 }
133
134 CHIP_ERROR ExchangeManager::UnregisterUnsolicitedMessageHandlerForProtocol(Protocols::Id protocolId)
135 {
136     return UnregisterUMH(protocolId, kAnyMessageType);
137 }
138
139 CHIP_ERROR ExchangeManager::UnregisterUnsolicitedMessageHandlerForType(Protocols::Id protocolId, uint8_t msgType)
140 {
141     return UnregisterUMH(protocolId, static_cast<int16_t>(msgType));
142 }
143
144 void ExchangeManager::OnReceiveError(CHIP_ERROR error, const Transport::PeerAddress & source, SecureSessionMgr * msgLayer)
145 {
146     ChipLogError(ExchangeManager, "Accept FAILED, err = %s", ErrorStr(error));
147 }
148
149 ExchangeContext * ExchangeManager::AllocContext(uint16_t ExchangeId, SecureSessionHandle session, bool Initiator,
150                                                 ExchangeDelegate * delegate)
151 {
152     CHIP_FAULT_INJECT(FaultInjection::kFault_AllocExchangeContext, return nullptr);
153
154     for (auto & ec : mContextPool)
155     {
156         if (ec.GetReferenceCount() == 0)
157         {
158             return ec.Alloc(this, ExchangeId, session, Initiator, delegate);
159         }
160     }
161
162     ChipLogError(ExchangeManager, "Alloc ctxt FAILED");
163     return nullptr;
164 }
165
166 CHIP_ERROR ExchangeManager::RegisterUMH(Protocols::Id protocolId, int16_t msgType, ExchangeDelegate * delegate)
167 {
168     UnsolicitedMessageHandler * umh      = UMHandlerPool;
169     UnsolicitedMessageHandler * selected = nullptr;
170
171     for (int i = 0; i < CHIP_CONFIG_MAX_UNSOLICITED_MESSAGE_HANDLERS; i++, umh++)
172     {
173         if (!umh->IsInUse())
174         {
175             if (selected == nullptr)
176                 selected = umh;
177         }
178         else if (umh->Matches(protocolId, msgType))
179         {
180             umh->Delegate = delegate;
181             return CHIP_NO_ERROR;
182         }
183     }
184
185     if (selected == nullptr)
186         return CHIP_ERROR_TOO_MANY_UNSOLICITED_MESSAGE_HANDLERS;
187
188     selected->Delegate    = delegate;
189     selected->ProtocolId  = protocolId;
190     selected->MessageType = msgType;
191
192     SYSTEM_STATS_INCREMENT(chip::System::Stats::kExchangeMgr_NumUMHandlers);
193
194     return CHIP_NO_ERROR;
195 }
196
197 CHIP_ERROR ExchangeManager::UnregisterUMH(Protocols::Id protocolId, int16_t msgType)
198 {
199     UnsolicitedMessageHandler * umh = UMHandlerPool;
200
201     for (int i = 0; i < CHIP_CONFIG_MAX_UNSOLICITED_MESSAGE_HANDLERS; i++, umh++)
202     {
203         if (umh->IsInUse() && umh->Matches(protocolId, msgType))
204         {
205             umh->Reset();
206             SYSTEM_STATS_DECREMENT(chip::System::Stats::kExchangeMgr_NumUMHandlers);
207             return CHIP_NO_ERROR;
208         }
209     }
210
211     return CHIP_ERROR_NO_UNSOLICITED_MESSAGE_HANDLER;
212 }
213
214 bool ExchangeManager::IsMsgCounterSyncMessage(const PayloadHeader & payloadHeader)
215 {
216     if (payloadHeader.HasMessageType(Protocols::SecureChannel::MsgType::MsgCounterSyncReq) ||
217         payloadHeader.HasMessageType(Protocols::SecureChannel::MsgType::MsgCounterSyncRsp))
218     {
219         return true;
220     }
221
222     return false;
223 }
224
225 void ExchangeManager::HandleGroupMessageReceived(const PacketHeader & packetHeader, const PayloadHeader & payloadHeader,
226                                                  const SecureSessionHandle & session, System::PacketBufferHandle msgBuf)
227 {
228     OnMessageReceived(packetHeader, payloadHeader, session, std::move(msgBuf), nullptr);
229 }
230
231 void ExchangeManager::OnMessageReceived(const PacketHeader & packetHeader, const PayloadHeader & payloadHeader,
232                                         SecureSessionHandle session, System::PacketBufferHandle msgBuf, SecureSessionMgr * msgLayer)
233 {
234     CHIP_ERROR err                          = CHIP_NO_ERROR;
235     UnsolicitedMessageHandler * umh         = nullptr;
236     UnsolicitedMessageHandler * matchingUMH = nullptr;
237     bool sendAckAndCloseExchange            = false;
238
239     if (!IsMsgCounterSyncMessage(payloadHeader) && session.IsPeerGroupMsgIdNotSynchronized())
240     {
241         Transport::PeerConnectionState * state = mSessionMgr->GetPeerConnectionState(session);
242         VerifyOrReturn(state != nullptr);
243
244         // Queue the message as needed for sync with destination node.
245         err = mMessageCounterSyncMgr.AddToReceiveTable(packetHeader, payloadHeader, session, std::move(msgBuf));
246         VerifyOrReturn(err == CHIP_NO_ERROR);
247
248         // Initiate message counter synchronization if no message counter synchronization is in progress.
249         if (!state->IsMsgCounterSyncInProgress())
250         {
251             err = mMessageCounterSyncMgr.SendMsgCounterSyncReq(session);
252         }
253
254         if (err != CHIP_NO_ERROR)
255         {
256             ChipLogError(ExchangeManager,
257                          "Message counter synchronization for received message, failed to send synchronization request, err = %d",
258                          err);
259         }
260
261         // After the message that triggers message counter synchronization is stored, and a message counter
262         // synchronization exchange is initiated, we need to return immediately and re-process the original message
263         // when the synchronization is completed.
264
265         return;
266     }
267
268     // Search for an existing exchange that the message applies to. If a match is found...
269     for (auto & ec : mContextPool)
270     {
271         if (ec.GetReferenceCount() > 0 && ec.MatchExchange(session, packetHeader, payloadHeader))
272         {
273             // Found a matching exchange. Set flag for correct subsequent CRMP
274             // retransmission timeout selection.
275             if (!ec.mReliableMessageContext.HasRcvdMsgFromPeer())
276             {
277                 ec.mReliableMessageContext.SetMsgRcvdFromPeer(true);
278             }
279
280             // Matched ExchangeContext; send to message handler.
281             ec.HandleMessage(packetHeader, payloadHeader, std::move(msgBuf));
282
283             ExitNow(err = CHIP_NO_ERROR);
284         }
285     }
286
287     // Search for an unsolicited message handler if it marked as being sent by an initiator. Since we didn't
288     // find an existing exchange that matches the message, it must be an unsolicited message. However all
289     // unsolicited messages must be marked as being from an initiator.
290     if (payloadHeader.IsInitiator())
291     {
292         // Search for an unsolicited message handler that can handle the message. Prefer handlers that can explicitly
293         // handle the message type over handlers that handle all messages for a profile.
294         umh = (UnsolicitedMessageHandler *) UMHandlerPool;
295
296         matchingUMH = nullptr;
297
298         for (int i = 0; i < CHIP_CONFIG_MAX_UNSOLICITED_MESSAGE_HANDLERS; i++, umh++)
299         {
300             if (umh->IsInUse() && payloadHeader.HasProtocol(umh->ProtocolId))
301             {
302                 if (umh->MessageType == payloadHeader.GetMessageType())
303                 {
304                     matchingUMH = umh;
305                     break;
306                 }
307
308                 if (umh->MessageType == kAnyMessageType)
309                     matchingUMH = umh;
310             }
311         }
312     }
313     // Discard the message if it isn't marked as being sent by an initiator and the message does not need to send
314     // an ack to the peer.
315     else if (!payloadHeader.NeedsAck())
316     {
317         ExitNow(err = CHIP_ERROR_UNSOLICITED_MSG_NO_ORIGINATOR);
318     }
319
320     // If we didn't find an existing exchange that matches the message, and no unsolicited message handler registered
321     // to hand this message, we need to create a temporary exchange to send an ack for this message and then close this exchange.
322     sendAckAndCloseExchange = payloadHeader.NeedsAck() && (matchingUMH == nullptr);
323
324     // If we found a handler or we need to create a new exchange context (EC).
325     if (matchingUMH != nullptr || sendAckAndCloseExchange)
326     {
327         ExchangeContext * ec = nullptr;
328
329         if (sendAckAndCloseExchange)
330         {
331             // If rcvd msg is from initiator then this exchange is created as not Initiator.
332             // If rcvd msg is not from initiator then this exchange is created as Initiator.
333             ec = AllocContext(payloadHeader.GetExchangeID(), session, !payloadHeader.IsInitiator(), nullptr);
334         }
335         else
336         {
337             ec = AllocContext(payloadHeader.GetExchangeID(), session, false, matchingUMH->Delegate);
338         }
339
340         VerifyOrExit(ec != nullptr, err = CHIP_ERROR_NO_MEMORY);
341
342         ChipLogProgress(ExchangeManager, "ec pos: %d, id: %d, Delegate: 0x%x", ec - mContextPool.begin(), ec->GetExchangeId(),
343                         ec->GetDelegate());
344
345         ec->HandleMessage(packetHeader, payloadHeader, std::move(msgBuf));
346
347         // Close exchange if it was created only to send ack for a duplicate message.
348         if (sendAckAndCloseExchange)
349             ec->Close();
350     }
351
352 exit:
353     if (err != CHIP_NO_ERROR)
354     {
355         ChipLogError(ExchangeManager, "OnMessageReceived failed, err = %d", err);
356     }
357 }
358
359 ChannelHandle ExchangeManager::EstablishChannel(const ChannelBuilder & builder, ChannelDelegate * delegate)
360 {
361     ChannelContext * channelContext = nullptr;
362
363     // Find an existing Channel matching the builder
364     mChannelContexts.ForEachActiveObject([&](ChannelContext * context) {
365         if (context->MatchesBuilder(builder))
366         {
367             channelContext = context;
368             return false;
369         }
370         return true;
371     });
372
373     if (channelContext == nullptr)
374     {
375         // create a new channel if not found
376         channelContext = mChannelContexts.CreateObject(this);
377         if (channelContext == nullptr)
378             return ChannelHandle{ nullptr };
379         channelContext->Start(builder);
380     }
381     else
382     {
383         channelContext->Retain();
384     }
385
386     ChannelContextHandleAssociation * association = mChannelHandles.CreateObject(channelContext, delegate);
387     channelContext->Release();
388     return ChannelHandle{ association };
389 }
390
391 void ExchangeManager::OnNewConnection(SecureSessionHandle session, SecureSessionMgr * mgr)
392 {
393     mChannelContexts.ForEachActiveObject([&](ChannelContext * context) {
394         if (context->MatchesSession(session, mgr))
395         {
396             context->OnNewConnection(session);
397             return false;
398         }
399         return true;
400     });
401 }
402
403 void ExchangeManager::OnConnectionExpired(SecureSessionHandle session, SecureSessionMgr * mgr)
404 {
405     for (auto & ec : mContextPool)
406     {
407         if (ec.GetReferenceCount() > 0 && ec.mSecureSession == session)
408         {
409             ec.Close();
410             // Continue iterate because there can be multiple contexts associated with the connection.
411         }
412     }
413
414     mChannelContexts.ForEachActiveObject([&](ChannelContext * context) {
415         if (context->MatchesSession(session, mgr))
416         {
417             context->OnConnectionExpired(session);
418             return false;
419         }
420         return true;
421     });
422 }
423
424 void ExchangeManager::OnMessageReceived(const PacketHeader & header, const Transport::PeerAddress & source,
425                                         System::PacketBufferHandle msgBuf)
426 {
427     auto peer = header.GetSourceNodeId();
428     if (!peer.HasValue())
429     {
430         char addrBuffer[Transport::PeerAddress::kMaxToStringSize];
431         source.ToString(addrBuffer, sizeof(addrBuffer));
432         ChipLogError(ExchangeManager, "Unencrypted message from %s is dropped since no source node id in packet header.",
433                      addrBuffer);
434         return;
435     }
436
437     auto node     = peer.Value();
438     auto notFound = mChannelContexts.ForEachActiveObject([&](ChannelContext * context) {
439         if (context->IsCasePairing() && context->MatchNodeId(node))
440         {
441             CHIP_ERROR err = context->HandlePairingMessage(header, source, std::move(msgBuf));
442             if (err != CHIP_NO_ERROR)
443                 ChipLogError(ExchangeManager, "HandlePairingMessage error %s from node 0x%08" PRIx32 "%08" PRIx32 ".",
444                              chip::ErrorStr(err), static_cast<uint32_t>(node >> 32), static_cast<uint32_t>(node));
445             return false;
446         }
447         return true;
448     });
449
450     if (notFound)
451     {
452         char addrBuffer[Transport::PeerAddress::kMaxToStringSize];
453         source.ToString(addrBuffer, sizeof(addrBuffer));
454         ChipLogError(ExchangeManager,
455                      "Unencrypted message from %s is dropped since no session found for node 0x%08" PRIx32 "%08" PRIx32 ".",
456                      addrBuffer, static_cast<uint32_t>(node >> 32), static_cast<uint32_t>(node));
457         return;
458     }
459 }
460
461 void ExchangeManager::IncrementContextsInUse()
462 {
463     mContextsInUse++;
464 }
465
466 void ExchangeManager::DecrementContextsInUse()
467 {
468     if (mContextsInUse >= 1)
469     {
470         mContextsInUse--;
471     }
472     else
473     {
474         ChipLogError(ExchangeManager, "No context in use, decrement failed");
475     }
476 }
477
478 } // namespace Messaging
479 } // namespace chip