Line data Source code
1 : /*
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/InteractionModelTimeout.h>
21 : #include <app/MessageDef/TimedRequestMessage.h>
22 : #include <app/StatusResponse.h>
23 : #include <lib/core/TLV.h>
24 : #include <lib/support/logging/CHIPLogging.h>
25 : #include <system/SystemClock.h>
26 : #include <system/TLVPacketBufferBackingStore.h>
27 :
28 : namespace chip {
29 : namespace app {
30 :
31 9 : CHIP_ERROR TimedHandler::OnMessageReceived(Messaging::ExchangeContext * aExchangeContext, const PayloadHeader & aPayloadHeader,
32 : System::PacketBufferHandle && aPayload)
33 : {
34 : using namespace Protocols::InteractionModel;
35 :
36 9 : 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 0 : ChipLogError(DataManagement, "Dropping Timed Request on group exchange " ChipLogFormatExchange,
41 : ChipLogValueExchange(aExchangeContext));
42 0 : return CHIP_NO_ERROR;
43 : }
44 :
45 9 : 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 5 : VerifyOrDie(aPayloadHeader.HasMessageType(MsgType::TimedRequest));
50 5 : mState = State::kReceivedTimedAction;
51 5 : CHIP_ERROR err = HandleTimedRequestAction(aExchangeContext, aPayloadHeader, std::move(aPayload));
52 5 : if (err != CHIP_NO_ERROR)
53 : {
54 0 : ChipLogError(DataManagement, "Failed to parse Timed Request action: handler %p exchange " ChipLogFormatExchange, this,
55 : ChipLogValueExchange(aExchangeContext));
56 0 : StatusResponse::Send(Status::InvalidAction, aExchangeContext, /* aExpectResponse = */ false);
57 : }
58 5 : return err;
59 : }
60 :
61 4 : if (mState == State::kExpectingFollowingAction)
62 : {
63 4 : System::Clock::Timestamp now = System::SystemClock().GetMonotonicTimestamp();
64 4 : ChipLogDetail(DataManagement,
65 : "Timed following action arrived at 0x" ChipLogFormatX64 ": handler %p exchange " ChipLogFormatExchange,
66 : ChipLogValueX64(now.count()), this, ChipLogValueExchange(aExchangeContext));
67 4 : if (now > mTimeLimit)
68 : {
69 2 : ChipLogError(DataManagement, "Timeout expired: handler %p exchange " ChipLogFormatExchange, this,
70 : ChipLogValueExchange(aExchangeContext));
71 4 : return StatusResponse::Send(Status::Timeout, aExchangeContext, /* aExpectResponse = */ false);
72 : }
73 :
74 2 : if (aPayloadHeader.HasMessageType(MsgType::InvokeCommandRequest))
75 : {
76 1 : ChipLogDetail(DataManagement, "Handing timed invoke to IM engine: handler %p exchange " ChipLogFormatExchange, this,
77 : ChipLogValueExchange(aExchangeContext));
78 1 : mDelegate->OnTimedInvoke(this, aExchangeContext, aPayloadHeader, std::move(aPayload));
79 1 : return CHIP_NO_ERROR;
80 : }
81 :
82 1 : if (aPayloadHeader.HasMessageType(MsgType::WriteRequest))
83 : {
84 1 : ChipLogDetail(DataManagement, "Handing timed write to IM engine: handler %p exchange " ChipLogFormatExchange, this,
85 : ChipLogValueExchange(aExchangeContext));
86 1 : mDelegate->OnTimedWrite(this, aExchangeContext, aPayloadHeader, std::move(aPayload));
87 1 : return CHIP_NO_ERROR;
88 : }
89 : }
90 :
91 : // Not an expected message. Send an error response. The exchange will
92 : // close when we return.
93 0 : ChipLogError(DataManagement, "Unexpected unknown message in tiemd interaction: handler %p exchange " ChipLogFormatExchange,
94 : this, ChipLogValueExchange(aExchangeContext));
95 :
96 0 : return StatusResponse::Send(Status::InvalidAction, aExchangeContext, /* aExpectResponse = */ false);
97 : }
98 :
99 2 : void TimedHandler::OnExchangeClosing(Messaging::ExchangeContext *)
100 : {
101 2 : mDelegate->OnTimedInteractionFailed(this);
102 2 : }
103 :
104 5 : CHIP_ERROR TimedHandler::HandleTimedRequestAction(Messaging::ExchangeContext * aExchangeContext,
105 : const PayloadHeader & aPayloadHeader, System::PacketBufferHandle && aPayload)
106 : {
107 : using namespace Protocols::InteractionModel;
108 :
109 5 : System::PacketBufferTLVReader reader;
110 5 : reader.Init(std::move(aPayload));
111 5 : TimedRequestMessage::Parser parser;
112 5 : ReturnErrorOnFailure(parser.Init(reader));
113 :
114 : #if CHIP_CONFIG_IM_PRETTY_PRINT
115 5 : parser.PrettyPrint();
116 : #endif
117 :
118 : uint16_t timeoutMs;
119 5 : ReturnErrorOnFailure(parser.GetTimeoutMs(&timeoutMs));
120 5 : ReturnErrorOnFailure(parser.ExitContainer());
121 :
122 5 : ChipLogDetail(DataManagement, "Got Timed Request with timeout %u: handler %p exchange " ChipLogFormatExchange, timeoutMs, this,
123 : ChipLogValueExchange(aExchangeContext));
124 : // Use at least our default IM timeout, because if we close our exchange as
125 : // soon as we know the delay has passed we won't be able to send the
126 : // UNSUPPORTED_ACCESS status code the spec tells us to send (and in fact
127 : // will send nothing and the other side will have to time out to realize
128 : // it's missed its window).
129 5 : auto delay = System::Clock::Milliseconds32(timeoutMs);
130 5 : aExchangeContext->SetResponseTimeout(
131 10 : std::max(delay, aExchangeContext->GetSessionHandle()->ComputeRoundTripTimeout(app::kExpectedIMProcessingTime)));
132 5 : ReturnErrorOnFailure(StatusResponse::Send(Status::Success, aExchangeContext, /* aExpectResponse = */ true));
133 :
134 : // Now just wait for the client.
135 5 : mState = State::kExpectingFollowingAction;
136 5 : mTimeLimit = System::SystemClock().GetMonotonicTimestamp() + delay;
137 5 : ChipLogDetail(DataManagement, "Timed Request time limit 0x" ChipLogFormatX64 ": handler %p exchange " ChipLogFormatExchange,
138 : ChipLogValueX64(mTimeLimit.count()), this, ChipLogValueExchange(aExchangeContext));
139 5 : return CHIP_NO_ERROR;
140 5 : }
141 :
142 : } // namespace app
143 : } // namespace chip
|