Implement ExchangeManager for messaging layer (#3290)

* Implement ExchangeManager for messaging layer

* Update OnMessageReceived API documentation

* Remove unused header include and use static constexpr instead of enum for typesafety

* Restyled by clang-format

* Address the review comments
diff --git a/src/messaging/ExchangeMgr.cpp b/src/messaging/ExchangeMgr.cpp
new file mode 100644
index 0000000..bd3f453
--- /dev/null
+++ b/src/messaging/ExchangeMgr.cpp
@@ -0,0 +1,343 @@
+/*
+ *
+ *    Copyright (c) 2020 Project CHIP Authors
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+/**
+ *    @file
+ *      This file implements the ExchangeManager class.
+ *
+ */
+
+#ifndef __STDC_FORMAT_MACROS
+#define __STDC_FORMAT_MACROS
+#endif
+
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS
+#endif
+
+#include <inttypes.h>
+#include <stddef.h>
+
+#include <core/CHIPCore.h>
+#include <core/CHIPEncoding.h>
+#include <messaging/ExchangeContext.h>
+#include <messaging/ExchangeMgr.h>
+#include <support/CHIPFaultInjection.h>
+#include <support/CodeUtils.h>
+#include <support/RandUtils.h>
+#include <support/logging/CHIPLogging.h>
+
+using namespace chip::Encoding;
+using namespace chip::Inet;
+using namespace chip::System;
+
+namespace chip {
+
+/**
+ *  Constructor for the ExchangeManager class.
+ *  It sets the state to kState_NotInitialized.
+ *
+ *  @note
+ *    The class must be initialized via ExchangeManager::Init()
+ *    prior to use.
+ *
+ */
+ExchangeManager::ExchangeManager()
+{
+    mState = State::kState_NotInitialized;
+}
+
+CHIP_ERROR ExchangeManager::Init(SecureSessionMgrBase * sessionMgr)
+{
+    if (mState != State::kState_NotInitialized)
+        return CHIP_ERROR_INCORRECT_STATE;
+
+    mSessionMgr = sessionMgr;
+
+    mNextExchangeId = GetRandU16();
+
+    memset(ContextPool, 0, sizeof(ContextPool));
+    mContextsInUse = 0;
+
+    memset(UMHandlerPool, 0, sizeof(UMHandlerPool));
+    OnExchangeContextChanged = nullptr;
+
+    sessionMgr->SetDelegate(this);
+
+    mState = State::kState_Initialized;
+
+    return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR ExchangeManager::Shutdown()
+{
+    if (mSessionMgr != nullptr)
+    {
+        mSessionMgr->SetDelegate(nullptr);
+        mSessionMgr = nullptr;
+    }
+
+    OnExchangeContextChanged = nullptr;
+
+    mState = State::kState_NotInitialized;
+
+    return CHIP_NO_ERROR;
+}
+
+ExchangeContext * ExchangeManager::NewContext(const uint64_t & peerNodeId, void * appState)
+{
+    ExchangeContext * ec = AllocContext();
+
+    if (ec != nullptr)
+    {
+        ec->SetExchangeId(mNextExchangeId++);
+        ec->SetPeerNodeId(peerNodeId);
+        ec->SetAppState(appState);
+        ec->SetInitiator(true);
+        ChipLogProgress(ExchangeManager, "ec id: %d, AppState: 0x%x", (ec - ContextPool + 1), ec->GetAppState());
+    }
+
+    return ec;
+}
+
+ExchangeContext * ExchangeManager::FindContext(uint64_t peerNodeId, void * appState, bool isInitiator)
+{
+    ExchangeContext * ec = ContextPool;
+
+    for (int i = 0; i < CHIP_CONFIG_MAX_EXCHANGE_CONTEXTS; i++, ec++)
+    {
+        if (ec->GetExchangeMgr() != nullptr && ec->GetPeerNodeId() == peerNodeId && ec->GetAppState() == appState &&
+            ec->IsInitiator() == isInitiator)
+            return ec;
+    }
+
+    return nullptr;
+}
+
+CHIP_ERROR ExchangeManager::RegisterUnsolicitedMessageHandler(uint32_t protocolId, ExchangeContext::MessageReceiveFunct handler,
+                                                              void * appState)
+{
+    return RegisterUMH(protocolId, kAnyMessageType, handler, appState);
+}
+
+CHIP_ERROR ExchangeManager::RegisterUnsolicitedMessageHandler(uint32_t protocolId, uint8_t msgType,
+                                                              ExchangeContext::MessageReceiveFunct handler, void * appState)
+{
+    return RegisterUMH(protocolId, static_cast<int16_t>(msgType), handler, appState);
+}
+
+CHIP_ERROR ExchangeManager::UnregisterUnsolicitedMessageHandler(uint32_t protocolId)
+{
+    return UnregisterUMH(protocolId, kAnyMessageType);
+}
+
+CHIP_ERROR ExchangeManager::UnregisterUnsolicitedMessageHandler(uint32_t protocolId, uint8_t msgType)
+{
+    return UnregisterUMH(protocolId, static_cast<int16_t>(msgType));
+}
+
+void ExchangeManager::OnReceiveError(CHIP_ERROR error, const Transport::PeerAddress & source, SecureSessionMgrBase * msgLayer)
+{
+    ChipLogError(ExchangeManager, "Accept FAILED, err = %s", ErrorStr(error));
+}
+
+ExchangeContext * ExchangeManager::AllocContext()
+{
+    ExchangeContext * ec = ContextPool;
+
+    CHIP_FAULT_INJECT(FaultInjection::kFault_AllocExchangeContext, return nullptr);
+
+    for (int i = 0; i < CHIP_CONFIG_MAX_EXCHANGE_CONTEXTS; i++, ec++)
+    {
+        if (ec->GetExchangeMgr() == nullptr)
+        {
+            *ec = ExchangeContext();
+            ec->SetExchangeMgr(this);
+            ec->SetRefCount(1);
+            mContextsInUse++;
+
+#if defined(CHIP_EXCHANGE_CONTEXT_DETAIL_LOGGING)
+            ChipLogProgress(ExchangeManager, "ec++ id: %d, inUse: %d, addr: 0x%x", (ec - ContextPool + 1), mContextsInUse, ec);
+#endif
+            SYSTEM_STATS_INCREMENT(chip::System::Stats::kExchangeMgr_NumContexts);
+
+            return ec;
+        }
+    }
+
+    ChipLogError(ExchangeManager, "Alloc ctxt FAILED");
+    return nullptr;
+}
+
+void ExchangeManager::DispatchMessage(const PacketHeader & packetHeader, const PayloadHeader & payloadHeader, PacketBuffer * msgBuf)
+{
+    UnsolicitedMessageHandler * umh         = nullptr;
+    UnsolicitedMessageHandler * matchingUMH = nullptr;
+    ExchangeContext * ec                    = nullptr;
+    CHIP_ERROR err                          = CHIP_NO_ERROR;
+
+    // Search for an existing exchange that the message applies to. If a match is found...
+    ec = ContextPool;
+    for (int i = 0; i < CHIP_CONFIG_MAX_EXCHANGE_CONTEXTS; i++, ec++)
+    {
+        if (ec->GetExchangeMgr() != nullptr && ec->MatchExchange(packetHeader, payloadHeader))
+        {
+            // Matched ExchangeContext; send to message handler.
+            ec->HandleMessage(packetHeader, payloadHeader, msgBuf);
+
+            msgBuf = nullptr;
+
+            ExitNow(err = CHIP_NO_ERROR);
+        }
+    }
+
+    // Search for an unsolicited message handler if it marked as being sent by an initiator. Since we didn't
+    // find an existing exchange that matches the message, it must be an unsolicited message. However all
+    // unsolicited messages must be marked as being from an initiator.
+    if (payloadHeader.IsInitiator())
+    {
+        // Search for an unsolicited message handler that can handle the message. Prefer handlers that can explicitly
+        // handle the message type over handlers that handle all messages for a profile.
+        umh = (UnsolicitedMessageHandler *) UMHandlerPool;
+
+        matchingUMH = nullptr;
+
+        for (int i = 0; i < CHIP_CONFIG_MAX_UNSOLICITED_MESSAGE_HANDLERS; i++, umh++)
+        {
+            if (umh->Handler != nullptr && umh->ProtocolId == payloadHeader.GetProtocolID())
+            {
+                if (umh->MessageType == payloadHeader.GetMessageType())
+                {
+                    matchingUMH = umh;
+                    break;
+                }
+
+                if (umh->MessageType == kAnyMessageType)
+                    matchingUMH = umh;
+            }
+        }
+    }
+    // Discard the message if it isn't marked as being sent by an initiator.
+    else
+    {
+        ExitNow(err = CHIP_ERROR_UNSOLICITED_MSG_NO_ORIGINATOR);
+    }
+
+    // If we found a handler or we need to create a new exchange context (EC).
+    if (matchingUMH != nullptr)
+    {
+        ExchangeContext::MessageReceiveFunct umhandler = nullptr;
+
+        ec = AllocContext();
+        VerifyOrExit(ec != nullptr, err = CHIP_ERROR_NO_MEMORY);
+
+        ec->SetExchangeId(payloadHeader.GetExchangeID());
+        ec->SetPeerNodeId(packetHeader.GetSourceNodeId().Value());
+        ec->SetInitiator(false);
+        ec->SetAppState(matchingUMH->AppState);
+
+        umhandler = matchingUMH->Handler;
+
+        ChipLogProgress(ExchangeManager, "ec id: %d, AppState: 0x%x", (ec - ContextPool + 1), ec->GetAppState());
+
+        ec->HandleMessage(packetHeader, payloadHeader, msgBuf, umhandler);
+        msgBuf = nullptr;
+    }
+
+exit:
+    if (err != CHIP_NO_ERROR)
+    {
+        ChipLogError(ExchangeManager, "DispatchMessage failed, err = %d", err);
+    }
+
+    if (msgBuf != nullptr)
+    {
+        PacketBuffer::Free(msgBuf);
+    }
+}
+
+CHIP_ERROR ExchangeManager::RegisterUMH(uint32_t protocolId, int16_t msgType, ExchangeContext::MessageReceiveFunct handler,
+                                        void * appState)
+{
+    UnsolicitedMessageHandler * umh      = UMHandlerPool;
+    UnsolicitedMessageHandler * selected = nullptr;
+
+    for (int i = 0; i < CHIP_CONFIG_MAX_UNSOLICITED_MESSAGE_HANDLERS; i++, umh++)
+    {
+        if (umh->Handler == nullptr)
+        {
+            if (selected == nullptr)
+                selected = umh;
+        }
+        else if (umh->ProtocolId == protocolId && umh->MessageType == msgType)
+        {
+            umh->Handler  = handler;
+            umh->AppState = appState;
+            return CHIP_NO_ERROR;
+        }
+    }
+
+    if (selected == nullptr)
+        return CHIP_ERROR_TOO_MANY_UNSOLICITED_MESSAGE_HANDLERS;
+
+    selected->Handler     = handler;
+    selected->AppState    = appState;
+    selected->ProtocolId  = protocolId;
+    selected->MessageType = msgType;
+
+    SYSTEM_STATS_INCREMENT(chip::System::Stats::kExchangeMgr_NumUMHandlers);
+
+    return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR ExchangeManager::UnregisterUMH(uint32_t protocolId, int16_t msgType)
+{
+    UnsolicitedMessageHandler * umh = UMHandlerPool;
+
+    for (int i = 0; i < CHIP_CONFIG_MAX_UNSOLICITED_MESSAGE_HANDLERS; i++, umh++)
+    {
+        if (umh->Handler != nullptr && umh->ProtocolId == protocolId && umh->MessageType == msgType)
+        {
+            umh->Handler = nullptr;
+            SYSTEM_STATS_DECREMENT(chip::System::Stats::kExchangeMgr_NumUMHandlers);
+            return CHIP_NO_ERROR;
+        }
+    }
+
+    return CHIP_ERROR_NO_UNSOLICITED_MESSAGE_HANDLER;
+}
+
+void ExchangeManager::OnMessageReceived(const PacketHeader & packetHeader, const PayloadHeader & payloadHeader,
+                                        Transport::PeerConnectionState * state, System::PacketBuffer * msgBuf,
+                                        SecureSessionMgrBase * msgLayer)
+{
+    DispatchMessage(packetHeader, payloadHeader, msgBuf);
+}
+
+void ExchangeManager::DecrementContextsInUse()
+{
+    if (mContextsInUse >= 1)
+    {
+        mContextsInUse--;
+    }
+    else
+    {
+        ChipLogError(ExchangeManager, "No context in use, decrement failed");
+    }
+}
+
+} // namespace chip