2 * Copyright (c) 2020-2021 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.
20 * This file implements the CHIP reliable message protocol.
26 #include <messaging/ExchangeContext.h>
27 #include <messaging/ReliableMessageContext.h>
29 #include <core/CHIPEncoding.h>
30 #include <messaging/ErrorCategory.h>
31 #include <messaging/Flags.h>
32 #include <messaging/ReliableMessageMgr.h>
33 #include <protocols/Protocols.h>
34 #include <protocols/secure_channel/Constants.h>
35 #include <support/CodeUtils.h>
40 ReliableMessageContext::ReliableMessageContext() :
41 mManager(nullptr), mExchange(nullptr), mDelegate(nullptr), mConfig(gDefaultReliableMessageProtocolConfig), mNextAckTimeTick(0),
45 void ReliableMessageContext::Init(ReliableMessageMgr * manager, ExchangeContext * exchange)
51 SetDropAckDebug(false);
53 SetPeerRequestedAck(false);
54 SetMsgRcvdFromPeer(false);
55 SetAutoRequestAck(true);
58 void ReliableMessageContext::Retain()
63 void ReliableMessageContext::Release()
68 bool ReliableMessageContext::AutoRequestAck() const
70 return mFlags.Has(Flags::kFlagAutoRequestAck);
73 bool ReliableMessageContext::IsAckPending() const
75 return mFlags.Has(Flags::kFlagAckPending);
78 bool ReliableMessageContext::HasPeerRequestedAck() const
80 return mFlags.Has(Flags::kFlagPeerRequestedAck);
83 bool ReliableMessageContext::HasRcvdMsgFromPeer() const
85 return mFlags.Has(Flags::kFlagMsgRcvdFromPeer);
88 void ReliableMessageContext::SetAutoRequestAck(bool autoReqAck)
90 mFlags.Set(Flags::kFlagAutoRequestAck, autoReqAck);
93 void ReliableMessageContext::SetMsgRcvdFromPeer(bool inMsgRcvdFromPeer)
95 mFlags.Set(Flags::kFlagMsgRcvdFromPeer, inMsgRcvdFromPeer);
98 void ReliableMessageContext::SetAckPending(bool inAckPending)
100 mFlags.Set(Flags::kFlagAckPending, inAckPending);
103 void ReliableMessageContext::SetPeerRequestedAck(bool inPeerRequestedAck)
105 mFlags.Set(Flags::kFlagPeerRequestedAck, inPeerRequestedAck);
108 void ReliableMessageContext::SetDropAckDebug(bool inDropAckDebug)
110 mFlags.Set(Flags::kFlagDropAckDebug, inDropAckDebug);
113 bool ReliableMessageContext::ShouldDropAckDebug() const
115 return mFlags.Has(Flags::kFlagDropAckDebug);
118 CHIP_ERROR ReliableMessageContext::FlushAcks()
120 CHIP_ERROR err = CHIP_NO_ERROR;
124 // Send the acknowledgment as a SecureChannel::StandStandaloneAck message
125 err = SendStandaloneAckMessage();
127 if (err == CHIP_NO_ERROR)
130 ChipLogProgress(ExchangeManager, "Flushed pending ack for MsgId:%08" PRIX32, mPendingPeerAckId);
138 uint64_t ReliableMessageContext::GetCurrentRetransmitTimeoutTick()
140 return (HasRcvdMsgFromPeer() ? mConfig.mActiveRetransTimeoutTick : mConfig.mInitialRetransTimeoutTick);
144 * Process received Ack. Remove the corresponding message context from the RetransTable and execute the application
148 * This message is part of the CHIP Reliable Messaging protocol.
150 * @param[in] AckMsgId The msgId of incoming Ack message.
152 * @retval #CHIP_ERROR_INVALID_ACK_ID if the msgId of received Ack is not in the RetransTable.
153 * @retval #CHIP_NO_ERROR if the context was removed.
156 CHIP_ERROR ReliableMessageContext::HandleRcvdAck(uint32_t AckMsgId)
158 CHIP_ERROR err = CHIP_NO_ERROR;
160 // Msg is an Ack; Check Retrans Table and remove message context
161 if (!mManager->CheckAndRemRetransTable(this, AckMsgId))
164 ChipLogError(ExchangeManager, "CHIP MsgId:%08" PRIX32 " not in RetransTable", AckMsgId);
166 err = CHIP_ERROR_INVALID_ACK_ID;
167 // Optionally call an application callback with this error.
173 mDelegate->OnAckRcvd();
177 ChipLogProgress(ExchangeManager, "Removed CHIP MsgId:%08" PRIX32 " from RetransTable", AckMsgId);
184 CHIP_ERROR ReliableMessageContext::HandleNeedsAck(uint32_t MessageId, BitFlags<MessageFlagValues> MsgFlags)
187 CHIP_ERROR err = CHIP_NO_ERROR;
189 // Skip processing ack if drop ack debug is enabled.
190 if (ShouldDropAckDebug())
193 // Expire any virtual ticks that have expired so all wakeup sources reflect the current time
194 mManager->ExpireTicks();
196 // If the message IS a duplicate.
197 if (MsgFlags.Has(MessageFlagValues::kDuplicateMessage))
200 ChipLogProgress(ExchangeManager, "Forcing tx of solitary ack for duplicate MsgId:%08" PRIX32, MessageId);
202 // Is there pending ack for a different message id.
203 bool wasAckPending = IsAckPending() && mPendingPeerAckId != MessageId;
205 // Temporary store currently pending ack id (even if there is none).
206 uint32_t tempAckId = mPendingPeerAckId;
208 // Set the pending ack id.
209 mPendingPeerAckId = MessageId;
211 // Send the Ack for the duplication message in a SecureChannel::StandaloneAck message.
212 err = SendStandaloneAckMessage();
214 // If there was pending ack for a different message id.
217 // Restore previously pending ack id.
218 mPendingPeerAckId = tempAckId;
224 // Otherwise, the message IS NOT a duplicate.
230 ChipLogProgress(ExchangeManager, "Pending ack queue full; forcing tx of solitary ack for MsgId:%08" PRIX32,
233 // Send the Ack for the currently pending Ack in a SecureChannel::StandaloneAck message.
234 err = SendStandaloneAckMessage();
238 // Replace the Pending ack id.
239 mPendingPeerAckId = MessageId;
240 mNextAckTimeTick = static_cast<uint16_t>(mConfig.mAckPiggybackTimeoutTick +
241 mManager->GetTickCounterFromTimeDelta(System::Timer::GetCurrentEpoch()));
246 // Schedule next physical wakeup
247 mManager->StartTimer();
251 CHIP_ERROR ReliableMessageContext::SendStandaloneAckMessage()
253 CHIP_ERROR err = CHIP_NO_ERROR;
255 // Allocate a buffer for the null message
256 System::PacketBufferHandle msgBuf = MessagePacketBuffer::New(0);
257 VerifyOrExit(!msgBuf.IsNull(), err = CHIP_ERROR_NO_MEMORY);
259 // Send the null message
260 if (mExchange != nullptr)
262 err = mExchange->SendMessage(Protocols::SecureChannel::MsgType::StandaloneAck, std::move(msgBuf),
263 BitFlags<SendMessageFlags>{ SendMessageFlags::kNoAutoRequestAck });
267 ChipLogError(ExchangeManager, "ExchangeContext is not initilized in ReliableMessageContext");
268 err = CHIP_ERROR_NOT_CONNECTED;
272 if (IsSendErrorNonCritical(err))
274 ChipLogError(ExchangeManager, "Non-crit err %ld sending solitary ack", long(err));
277 if (err != CHIP_NO_ERROR)
279 ChipLogError(ExchangeManager, "Failed to send Solitary ack for MsgId:%08" PRIX32 ":%ld", mPendingPeerAckId, (long) err);
285 } // namespace Messaging