blob: d448784721ac5904e59d6603c37c47f4b559e6f2 [file] [log] [blame]
Boris Zbarskyffee2a92021-12-01 14:34:57 -05001/*
2 *
3 * Copyright (c) 2020 Project CHIP Authors
4 * All rights reserved.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19#include "TimedHandler.h"
20#include <app/InteractionModelEngine.h>
21#include <app/MessageDef/TimedRequestMessage.h>
22#include <app/StatusResponse.h>
Martin Turon82bfcd52023-01-09 13:30:38 -080023#include <lib/core/TLV.h>
Boris Zbarskyffee2a92021-12-01 14:34:57 -050024#include <lib/support/logging/CHIPLogging.h>
25#include <system/SystemClock.h>
26#include <system/TLVPacketBufferBackingStore.h>
27
28namespace chip {
29namespace app {
30
31CHIP_ERROR TimedHandler::OnMessageReceived(Messaging::ExchangeContext * aExchangeContext, const PayloadHeader & aPayloadHeader,
32 System::PacketBufferHandle && aPayload)
33{
34 using namespace Protocols::InteractionModel;
35
36 if (aExchangeContext->IsGroupExchangeContext())
37 {
38 // Timed interactions are always supposed to be unicast. Nothing else
39 // to do here; exchange will close and we'll free ourselves.
40 ChipLogError(DataManagement, "Dropping Timed Request on group exchange " ChipLogFormatExchange,
41 ChipLogValueExchange(aExchangeContext));
42 return CHIP_NO_ERROR;
43 }
44
45 if (mState == State::kExpectingTimedAction)
46 {
47 // We were just created; our caller should have done this only if it's
48 // dealing with a Timed Request message.
49 VerifyOrDie(aPayloadHeader.HasMessageType(MsgType::TimedRequest));
50 mState = State::kReceivedTimedAction;
51 CHIP_ERROR err = HandleTimedRequestAction(aExchangeContext, aPayloadHeader, std::move(aPayload));
52 if (err != CHIP_NO_ERROR)
53 {
54 ChipLogError(DataManagement, "Failed to parse Timed Request action: handler %p exchange " ChipLogFormatExchange, this,
55 ChipLogValueExchange(aExchangeContext));
Boris Zbarskya02bce42021-12-01 16:57:25 -050056 StatusResponse::Send(Status::InvalidAction, aExchangeContext, /* aExpectResponse = */ false);
Boris Zbarskyffee2a92021-12-01 14:34:57 -050057 }
58 return err;
59 }
60
61 if (mState == State::kExpectingFollowingAction)
62 {
Boris Zbarsky70af2c42021-12-03 02:12:35 -050063 System::Clock::Timestamp now = System::SystemClock().GetMonotonicTimestamp();
64 ChipLogDetail(DataManagement,
65 "Timed following action arrived at 0x" ChipLogFormatX64 ": handler %p exchange " ChipLogFormatExchange,
66 ChipLogValueX64(now.count()), this, ChipLogValueExchange(aExchangeContext));
67 if (now > mTimeLimit)
Boris Zbarskyffee2a92021-12-01 14:34:57 -050068 {
69 // Time is up. Spec says to send UNSUPPORTED_ACCESS.
70 ChipLogError(DataManagement, "Timeout expired: handler %p exchange " ChipLogFormatExchange, this,
71 ChipLogValueExchange(aExchangeContext));
Boris Zbarskya02bce42021-12-01 16:57:25 -050072 return StatusResponse::Send(Status::UnsupportedAccess, aExchangeContext, /* aExpectResponse = */ false);
Boris Zbarskyffee2a92021-12-01 14:34:57 -050073 }
74
75 if (aPayloadHeader.HasMessageType(MsgType::InvokeCommandRequest))
76 {
77 auto * imEngine = InteractionModelEngine::GetInstance();
Boris Zbarskyffee2a92021-12-01 14:34:57 -050078 ChipLogDetail(DataManagement, "Handing timed invoke to IM engine: handler %p exchange " ChipLogFormatExchange, this,
79 ChipLogValueExchange(aExchangeContext));
80 imEngine->OnTimedInvoke(this, aExchangeContext, aPayloadHeader, std::move(aPayload));
81 return CHIP_NO_ERROR;
82 }
83
Boris Zbarsky653502d2021-12-02 04:01:47 -050084 if (aPayloadHeader.HasMessageType(MsgType::WriteRequest))
85 {
86 auto * imEngine = InteractionModelEngine::GetInstance();
87 ChipLogDetail(DataManagement, "Handing timed write to IM engine: handler %p exchange " ChipLogFormatExchange, this,
88 ChipLogValueExchange(aExchangeContext));
89 imEngine->OnTimedWrite(this, aExchangeContext, aPayloadHeader, std::move(aPayload));
90 return CHIP_NO_ERROR;
91 }
Boris Zbarskyffee2a92021-12-01 14:34:57 -050092 }
93
94 // Not an expected message. Send an error response. The exchange will
95 // close when we return.
96 ChipLogError(DataManagement, "Unexpected unknown message in tiemd interaction: handler %p exchange " ChipLogFormatExchange,
97 this, ChipLogValueExchange(aExchangeContext));
98
Boris Zbarskya02bce42021-12-01 16:57:25 -050099 return StatusResponse::Send(Status::InvalidAction, aExchangeContext, /* aExpectResponse = */ false);
Boris Zbarskyffee2a92021-12-01 14:34:57 -0500100}
101
102void TimedHandler::OnExchangeClosing(Messaging::ExchangeContext *)
103{
104 InteractionModelEngine::GetInstance()->OnTimedInteractionFailed(this);
105}
106
107CHIP_ERROR TimedHandler::HandleTimedRequestAction(Messaging::ExchangeContext * aExchangeContext,
108 const PayloadHeader & aPayloadHeader, System::PacketBufferHandle && aPayload)
109{
110 using namespace Protocols::InteractionModel;
111
112 System::PacketBufferTLVReader reader;
113 reader.Init(std::move(aPayload));
Boris Zbarskyffee2a92021-12-01 14:34:57 -0500114 TimedRequestMessage::Parser parser;
115 ReturnErrorOnFailure(parser.Init(reader));
116
yunhanw-google751d0dd2022-11-16 19:09:58 -0800117#if CHIP_CONFIG_IM_PRETTY_PRINT
118 parser.PrettyPrint();
Boris Zbarskyffee2a92021-12-01 14:34:57 -0500119#endif
120
121 uint16_t timeoutMs;
122 ReturnErrorOnFailure(parser.GetTimeoutMs(&timeoutMs));
yunhanw-google4394fcb2022-02-17 17:36:41 -0800123 ReturnErrorOnFailure(parser.ExitContainer());
Boris Zbarskyffee2a92021-12-01 14:34:57 -0500124
andrei-menzopol57471cb2022-04-20 23:31:17 +0300125 ChipLogDetail(DataManagement, "Got Timed Request with timeout %u: handler %p exchange " ChipLogFormatExchange, timeoutMs, this,
126 ChipLogValueExchange(aExchangeContext));
Boris Zbarskydc10c822021-12-02 06:55:34 -0500127 // Use at least our default IM timeout, because if we close our exchange as
128 // soon as we know the delay has passed we won't be able to send the
129 // UNSUPPORTED_ACCESS status code the spec tells us to send (and in fact
130 // will send nothing and the other side will have to time out to realize
131 // it's missed its window).
Boris Zbarskyffee2a92021-12-01 14:34:57 -0500132 auto delay = System::Clock::Milliseconds32(timeoutMs);
Song GUO2f6de7b2022-06-02 15:34:41 +0800133 aExchangeContext->SetResponseTimeout(
134 std::max(delay, aExchangeContext->GetSessionHandle()->ComputeRoundTripTimeout(app::kExpectedIMProcessingTime)));
Boris Zbarskya02bce42021-12-01 16:57:25 -0500135 ReturnErrorOnFailure(StatusResponse::Send(Status::Success, aExchangeContext, /* aExpectResponse = */ true));
Boris Zbarskyffee2a92021-12-01 14:34:57 -0500136
137 // Now just wait for the client.
138 mState = State::kExpectingFollowingAction;
139 mTimeLimit = System::SystemClock().GetMonotonicTimestamp() + delay;
Boris Zbarsky70af2c42021-12-03 02:12:35 -0500140 ChipLogDetail(DataManagement, "Timed Request time limit 0x" ChipLogFormatX64 ": handler %p exchange " ChipLogFormatExchange,
141 ChipLogValueX64(mTimeLimit.count()), this, ChipLogValueExchange(aExchangeContext));
Boris Zbarskyffee2a92021-12-01 14:34:57 -0500142 return CHIP_NO_ERROR;
143}
144
145} // namespace app
146} // namespace chip