| /* | 
 |  * | 
 |  *    Copyright (c) 2021 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 provides implementation of ExchangeMessageDispatch class. | 
 |  */ | 
 |  | 
 | #include <errno.h> | 
 | #include <inttypes.h> | 
 | #include <memory> | 
 |  | 
 | #include <lib/support/CodeUtils.h> | 
 | #include <messaging/ExchangeMessageDispatch.h> | 
 | #include <messaging/ReliableMessageContext.h> | 
 | #include <messaging/ReliableMessageMgr.h> | 
 | #include <protocols/secure_channel/Constants.h> | 
 |  | 
 | namespace chip { | 
 | namespace Messaging { | 
 |  | 
 | CHIP_ERROR ExchangeMessageDispatch::SendMessage(SessionManager * sessionManager, const SessionHandle & session, uint16_t exchangeId, | 
 |                                                 bool isInitiator, ReliableMessageContext * reliableMessageContext, | 
 |                                                 bool isReliableTransmission, Protocols::Id protocol, uint8_t type, | 
 |                                                 System::PacketBufferHandle && message) | 
 | { | 
 |     VerifyOrReturnError(MessagePermitted(protocol, type), CHIP_ERROR_INVALID_ARGUMENT); | 
 |  | 
 |     PayloadHeader payloadHeader; | 
 |     payloadHeader.SetExchangeID(exchangeId).SetMessageType(protocol, type).SetInitiator(isInitiator); | 
 |  | 
 |     if (session->AllowsMRP()) | 
 |     { | 
 |         // If there is a pending acknowledgment piggyback it on this message. | 
 |         if (reliableMessageContext->HasPiggybackAckPending()) | 
 |         { | 
 |             payloadHeader.SetAckMessageCounter(reliableMessageContext->TakePendingPeerAckMessageCounter()); | 
 |         } | 
 |  | 
 |         if (IsReliableTransmissionAllowed() && reliableMessageContext->AutoRequestAck() && | 
 |             reliableMessageContext->GetReliableMessageMgr() != nullptr && isReliableTransmission) | 
 |         { | 
 |             auto * reliableMessageMgr = reliableMessageContext->GetReliableMessageMgr(); | 
 |  | 
 |             payloadHeader.SetNeedsAck(true); | 
 |  | 
 |             ReliableMessageMgr::RetransTableEntry * entry = nullptr; | 
 |  | 
 |             // Add to Table for subsequent sending | 
 |             ReturnErrorOnFailure(reliableMessageMgr->AddToRetransTable(reliableMessageContext, &entry)); | 
 |             auto deleter = [reliableMessageMgr](ReliableMessageMgr::RetransTableEntry * e) { | 
 |                 reliableMessageMgr->ClearRetransTable(*e); | 
 |             }; | 
 |             std::unique_ptr<ReliableMessageMgr::RetransTableEntry, decltype(deleter)> entryOwner(entry, deleter); | 
 |  | 
 |             ReturnErrorOnFailure( | 
 |                 sessionManager->PrepareMessage(session, payloadHeader, std::move(message), entryOwner->retainedBuf)); | 
 |             CHIP_ERROR err = sessionManager->SendPreparedMessage(session, entryOwner->retainedBuf); | 
 |             err            = ReliableMessageMgr::MapSendError(err, exchangeId, isInitiator); | 
 |             ReturnErrorOnFailure(err); | 
 |             reliableMessageMgr->StartRetransmision(entryOwner.release()); | 
 |         } | 
 |         else | 
 |         { | 
 |             ReturnErrorOnFailure(PrepareAndSendNonMRPMessage(sessionManager, session, payloadHeader, std::move(message))); | 
 |         } | 
 |     } | 
 |     else | 
 |     { | 
 |         ReturnErrorOnFailure(PrepareAndSendNonMRPMessage(sessionManager, session, payloadHeader, std::move(message))); | 
 |     } | 
 |  | 
 |     return CHIP_NO_ERROR; | 
 | } | 
 |  | 
 | CHIP_ERROR ExchangeMessageDispatch::PrepareAndSendNonMRPMessage(SessionManager * sessionManager, const SessionHandle & session, | 
 |                                                                 PayloadHeader & payloadHeader, | 
 |                                                                 System::PacketBufferHandle && message) | 
 | { | 
 |     payloadHeader.SetNeedsAck(false); | 
 |     EncryptedPacketBufferHandle preparedMessage; | 
 |     ReturnErrorOnFailure(sessionManager->PrepareMessage(session, payloadHeader, std::move(message), preparedMessage)); | 
 |     ReturnErrorOnFailure(sessionManager->SendPreparedMessage(session, preparedMessage)); | 
 |  | 
 |     return CHIP_NO_ERROR; | 
 | } | 
 |  | 
 | } // namespace Messaging | 
 | } // namespace chip |