Skip to content

Commit d82ce57

Browse files
authored
Ensure that MRP logic is not executed for messages over other Transports (#30124)
* Ensure that MRP logic is not executed for messages over other Transports MRP based Ack handling and retransmissions should not be performed when messages are not sent using MRP, e.g., over TCP. Install guards on Send/Receive paths to steer traffic to bypass MRP logic when going over TCP. * Rename IsTransportTCP() to AllowsLargePayload()
1 parent b5dfe72 commit d82ce57

8 files changed

+112
-77
lines changed

src/messaging/ExchangeContext.cpp

+45-39
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ CHIP_ERROR ExchangeContext::SendMessage(Protocols::Id protocolId, uint8_t msgTyp
113113
// If session requires MRP, NoAutoRequestAck send flag is not specified and is not a group exchange context, request reliable
114114
// transmission.
115115
bool reliableTransmissionRequested =
116-
GetSessionHandle()->RequireMRP() && !sendFlags.Has(SendMessageFlags::kNoAutoRequestAck) && !IsGroupExchangeContext();
116+
GetSessionHandle()->AllowsMRP() && !sendFlags.Has(SendMessageFlags::kNoAutoRequestAck) && !IsGroupExchangeContext();
117117

118118
bool currentMessageExpectResponse = false;
119119
// If a response message is expected...
@@ -322,8 +322,8 @@ ExchangeContext::ExchangeContext(ExchangeManager * em, uint16_t ExchangeId, cons
322322

323323
SetAckPending(false);
324324

325-
// Do not request Ack for multicast
326-
SetAutoRequestAck(!session->IsGroupSession());
325+
// Try to use MRP by default, if it is allowed.
326+
SetAutoRequestAck(session->AllowsMRP());
327327

328328
#if CHIP_CONFIG_ENABLE_ICD_SERVER
329329
app::ICDNotifier::GetInstance().BroadcastActiveRequestNotification(app::ICDListener::KeepActiveFlag::kExchangeContextOpen);
@@ -531,58 +531,64 @@ CHIP_ERROR ExchangeContext::HandleMessage(uint32_t messageCounter, const Payload
531531
MessageHandled();
532532
});
533533

534-
if (mDispatch.IsReliableTransmissionAllowed() && !IsGroupExchangeContext())
534+
if (mSession->AllowsMRP())
535535
{
536-
if (!msgFlags.Has(MessageFlagValues::kDuplicateMessage) && payloadHeader.IsAckMsg() &&
537-
payloadHeader.GetAckMessageCounter().HasValue())
536+
if (mDispatch.IsReliableTransmissionAllowed())
538537
{
539-
HandleRcvdAck(payloadHeader.GetAckMessageCounter().Value());
538+
if (!msgFlags.Has(MessageFlagValues::kDuplicateMessage) && payloadHeader.IsAckMsg() &&
539+
payloadHeader.GetAckMessageCounter().HasValue())
540+
{
541+
HandleRcvdAck(payloadHeader.GetAckMessageCounter().Value());
542+
}
543+
544+
if (payloadHeader.NeedsAck())
545+
{
546+
// An acknowledgment needs to be sent back to the peer for this message on this exchange,
547+
HandleNeedsAck(messageCounter, msgFlags);
548+
}
540549
}
541550

542-
if (payloadHeader.NeedsAck())
551+
if (IsAckPending() && !mDelegate)
543552
{
544-
// An acknowledgment needs to be sent back to the peer for this message on this exchange,
545-
HandleNeedsAck(messageCounter, msgFlags);
553+
// The incoming message wants an ack, but we have no delegate, so
554+
// there's not going to be a response to piggyback on. Just flush the
555+
// ack out right now.
556+
ReturnErrorOnFailure(FlushAcks());
546557
}
547-
}
548558

549-
if (IsAckPending() && !mDelegate)
550-
{
551-
// The incoming message wants an ack, but we have no delegate, so
552-
// there's not going to be a response to piggyback on. Just flush the
553-
// ack out right now.
554-
ReturnErrorOnFailure(FlushAcks());
555-
}
556-
557-
// The SecureChannel::StandaloneAck message type is only used for MRP; do not pass such messages to the application layer.
558-
if (isStandaloneAck)
559-
{
560-
return CHIP_NO_ERROR;
561-
}
559+
// The SecureChannel::StandaloneAck message type is only used for MRP; do not pass such messages to the application layer.
560+
if (isStandaloneAck)
561+
{
562+
return CHIP_NO_ERROR;
563+
}
564+
} // AllowsMRP
562565

563566
// Since the message is duplicate, let's not forward it up the stack
564567
if (isDuplicate)
565568
{
566569
return CHIP_NO_ERROR;
567570
}
568571

569-
if (IsEphemeralExchange())
572+
if (mSession->AllowsMRP())
570573
{
571-
// The EphemeralExchange has done its job, since StandaloneAck is sent in previous FlushAcks() call.
572-
return CHIP_NO_ERROR;
573-
}
574+
if (IsEphemeralExchange())
575+
{
576+
// The EphemeralExchange has done its job, since StandaloneAck is sent in previous FlushAcks() call.
577+
return CHIP_NO_ERROR;
578+
}
574579

575-
if (IsWaitingForAck())
576-
{
577-
// The only way we can get here is a spec violation on the other side:
578-
// we sent a message that needs an ack, and the other side responded
579-
// with a message that does not contain an ack for the message we sent.
580-
// Just drop this message; if we delivered it to our delegate it might
581-
// try to send another message-needing-an-ack in response, which would
582-
// violate our internal invariants.
583-
ChipLogError(ExchangeManager, "Dropping message without piggyback ack when we are waiting for an ack.");
584-
return CHIP_ERROR_INCORRECT_STATE;
585-
}
580+
if (IsWaitingForAck())
581+
{
582+
// The only way we can get here is a spec violation on the other side:
583+
// we sent a message that needs an ack, and the other side responded
584+
// with a message that does not contain an ack for the message we sent.
585+
// Just drop this message; if we delivered it to our delegate it might
586+
// try to send another message-needing-an-ack in response, which would
587+
// violate our internal invariants.
588+
ChipLogError(ExchangeManager, "Dropping message without piggyback ack when we are waiting for an ack.");
589+
return CHIP_ERROR_INCORRECT_STATE;
590+
}
591+
} // AllowsMRP
586592

587593
#if CHIP_CONFIG_ENABLE_ICD_SERVER
588594
// message received

src/messaging/ExchangeMessageDispatch.cpp

+47-31
Original file line numberDiff line numberDiff line change
@@ -51,45 +51,61 @@ CHIP_ERROR ExchangeMessageDispatch::SendMessage(SessionManager * sessionManager,
5151
PayloadHeader payloadHeader;
5252
payloadHeader.SetExchangeID(exchangeId).SetMessageType(protocol, type).SetInitiator(isInitiator);
5353

54-
// If there is a pending acknowledgment piggyback it on this message.
55-
if (reliableMessageContext->HasPiggybackAckPending())
54+
if (session->AllowsMRP())
5655
{
57-
payloadHeader.SetAckMessageCounter(reliableMessageContext->TakePendingPeerAckMessageCounter());
58-
}
59-
60-
if (IsReliableTransmissionAllowed() && reliableMessageContext->AutoRequestAck() &&
61-
reliableMessageContext->GetReliableMessageMgr() != nullptr && isReliableTransmission)
62-
{
63-
auto * reliableMessageMgr = reliableMessageContext->GetReliableMessageMgr();
64-
65-
payloadHeader.SetNeedsAck(true);
66-
67-
ReliableMessageMgr::RetransTableEntry * entry = nullptr;
68-
69-
// Add to Table for subsequent sending
70-
ReturnErrorOnFailure(reliableMessageMgr->AddToRetransTable(reliableMessageContext, &entry));
71-
auto deleter = [reliableMessageMgr](ReliableMessageMgr::RetransTableEntry * e) {
72-
reliableMessageMgr->ClearRetransTable(*e);
73-
};
74-
std::unique_ptr<ReliableMessageMgr::RetransTableEntry, decltype(deleter)> entryOwner(entry, deleter);
75-
76-
ReturnErrorOnFailure(sessionManager->PrepareMessage(session, payloadHeader, std::move(message), entryOwner->retainedBuf));
77-
CHIP_ERROR err = sessionManager->SendPreparedMessage(session, entryOwner->retainedBuf);
78-
err = ReliableMessageMgr::MapSendError(err, exchangeId, isInitiator);
79-
ReturnErrorOnFailure(err);
80-
reliableMessageMgr->StartRetransmision(entryOwner.release());
56+
// If there is a pending acknowledgment piggyback it on this message.
57+
if (reliableMessageContext->HasPiggybackAckPending())
58+
{
59+
payloadHeader.SetAckMessageCounter(reliableMessageContext->TakePendingPeerAckMessageCounter());
60+
}
61+
62+
if (IsReliableTransmissionAllowed() && reliableMessageContext->AutoRequestAck() &&
63+
reliableMessageContext->GetReliableMessageMgr() != nullptr && isReliableTransmission)
64+
{
65+
auto * reliableMessageMgr = reliableMessageContext->GetReliableMessageMgr();
66+
67+
payloadHeader.SetNeedsAck(true);
68+
69+
ReliableMessageMgr::RetransTableEntry * entry = nullptr;
70+
71+
// Add to Table for subsequent sending
72+
ReturnErrorOnFailure(reliableMessageMgr->AddToRetransTable(reliableMessageContext, &entry));
73+
auto deleter = [reliableMessageMgr](ReliableMessageMgr::RetransTableEntry * e) {
74+
reliableMessageMgr->ClearRetransTable(*e);
75+
};
76+
std::unique_ptr<ReliableMessageMgr::RetransTableEntry, decltype(deleter)> entryOwner(entry, deleter);
77+
78+
ReturnErrorOnFailure(
79+
sessionManager->PrepareMessage(session, payloadHeader, std::move(message), entryOwner->retainedBuf));
80+
CHIP_ERROR err = sessionManager->SendPreparedMessage(session, entryOwner->retainedBuf);
81+
err = ReliableMessageMgr::MapSendError(err, exchangeId, isInitiator);
82+
ReturnErrorOnFailure(err);
83+
reliableMessageMgr->StartRetransmision(entryOwner.release());
84+
}
85+
else
86+
{
87+
ReturnErrorOnFailure(PrepareAndSendNonMRPMessage(sessionManager, session, payloadHeader, std::move(message)));
88+
}
8189
}
8290
else
8391
{
84-
// If the channel itself is providing reliability, let's not request MRP acks
85-
payloadHeader.SetNeedsAck(false);
86-
EncryptedPacketBufferHandle preparedMessage;
87-
ReturnErrorOnFailure(sessionManager->PrepareMessage(session, payloadHeader, std::move(message), preparedMessage));
88-
ReturnErrorOnFailure(sessionManager->SendPreparedMessage(session, preparedMessage));
92+
ReturnErrorOnFailure(PrepareAndSendNonMRPMessage(sessionManager, session, payloadHeader, std::move(message)));
8993
}
9094

9195
return CHIP_NO_ERROR;
9296
}
9397

98+
CHIP_ERROR ExchangeMessageDispatch::PrepareAndSendNonMRPMessage(SessionManager * sessionManager, const SessionHandle & session,
99+
PayloadHeader & payloadHeader,
100+
System::PacketBufferHandle && message)
101+
{
102+
payloadHeader.SetNeedsAck(false);
103+
EncryptedPacketBufferHandle preparedMessage;
104+
ReturnErrorOnFailure(sessionManager->PrepareMessage(session, payloadHeader, std::move(message), preparedMessage));
105+
ReturnErrorOnFailure(sessionManager->SendPreparedMessage(session, preparedMessage));
106+
107+
return CHIP_NO_ERROR;
108+
}
109+
94110
} // namespace Messaging
95111
} // namespace chip

src/messaging/ExchangeMessageDispatch.h

+4
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ class ExchangeMessageDispatch
4848

4949
// TODO: remove IsReliableTransmissionAllowed, this function should be provided over session.
5050
virtual bool IsReliableTransmissionAllowed() const { return true; }
51+
52+
private:
53+
CHIP_ERROR PrepareAndSendNonMRPMessage(SessionManager * sessionManager, const SessionHandle & session,
54+
PayloadHeader & payloadHeader, System::PacketBufferHandle && message);
5155
};
5256

5357
} // namespace Messaging

src/messaging/ExchangeMgr.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -372,8 +372,10 @@ void ExchangeManager::SendStandaloneAckIfNeeded(const PacketHeader & packetHeade
372372
const SessionHandle & session, MessageFlags msgFlags,
373373
System::PacketBufferHandle && msgBuf)
374374
{
375-
// If we need to send a StandaloneAck, create a EphemeralExchange for the purpose to send the StandaloneAck
376-
if (!payloadHeader.NeedsAck())
375+
376+
// If using the MRP protocol and we need to send a StandaloneAck, create an EphemeralExchange to send
377+
// the StandaloneAck.
378+
if (!session->AllowsMRP() || !payloadHeader.NeedsAck())
377379
return;
378380

379381
// If rcvd msg is from initiator then this exchange is created as not Initiator.

src/transport/GroupSession.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ class IncomingGroupSession : public Session, public ReferenceCounted<IncomingGro
5757
return subjectDescriptor;
5858
}
5959

60-
bool RequireMRP() const override { return false; }
60+
bool AllowsMRP() const override { return false; }
61+
bool AllowsLargePayload() const override { return false; }
6162

6263
const SessionParameters & GetRemoteSessionParameters() const override
6364
{
@@ -108,7 +109,8 @@ class OutgoingGroupSession : public Session, public ReferenceCounted<OutgoingGro
108109
return Access::SubjectDescriptor(); // no subject exists for outgoing group session.
109110
}
110111

111-
bool RequireMRP() const override { return false; }
112+
bool AllowsMRP() const override { return false; }
113+
bool AllowsLargePayload() const override { return false; }
112114

113115
const SessionParameters & GetRemoteSessionParameters() const override
114116
{

src/transport/SecureSession.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,9 @@ class SecureSession : public Session, public ReferenceCounted<SecureSession, Sec
156156

157157
Access::SubjectDescriptor GetSubjectDescriptor() const override;
158158

159-
bool RequireMRP() const override { return GetPeerAddress().GetTransportType() == Transport::Type::kUdp; }
159+
bool AllowsMRP() const override { return GetPeerAddress().GetTransportType() == Transport::Type::kUdp; }
160+
161+
bool AllowsLargePayload() const override { return GetPeerAddress().GetTransportType() == Transport::Type::kTcp; }
160162

161163
System::Clock::Milliseconds32 GetAckTimeout() const override
162164
{

src/transport/Session.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,8 @@ class Session
195195
virtual ScopedNodeId GetPeer() const = 0;
196196
virtual ScopedNodeId GetLocalScopedNodeId() const = 0;
197197
virtual Access::SubjectDescriptor GetSubjectDescriptor() const = 0;
198-
virtual bool RequireMRP() const = 0;
198+
virtual bool AllowsMRP() const = 0;
199+
virtual bool AllowsLargePayload() const = 0;
199200
virtual const SessionParameters & GetRemoteSessionParameters() const = 0;
200201
virtual System::Clock::Timestamp GetMRPBaseTimeout() const = 0;
201202
virtual System::Clock::Milliseconds32 GetAckTimeout() const = 0;

src/transport/UnauthenticatedSessionTable.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,9 @@ class UnauthenticatedSession : public Session, public ReferenceCounted<Unauthent
8383
return Access::SubjectDescriptor(); // return an empty ISD for unauthenticated session.
8484
}
8585

86-
bool RequireMRP() const override { return GetPeerAddress().GetTransportType() == Transport::Type::kUdp; }
86+
bool AllowsMRP() const override { return GetPeerAddress().GetTransportType() == Transport::Type::kUdp; }
87+
88+
bool AllowsLargePayload() const override { return GetPeerAddress().GetTransportType() == Transport::Type::kTcp; }
8789

8890
System::Clock::Milliseconds32 GetAckTimeout() const override
8991
{

0 commit comments

Comments
 (0)