Boris Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 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/InteractionModelEngine.h> |
| 21 | #include <app/MessageDef/TimedRequestMessage.h> |
| 22 | #include <app/StatusResponse.h> |
Martin Turon | 82bfcd5 | 2023-01-09 13:30:38 -0800 | [diff] [blame] | 23 | #include <lib/core/TLV.h> |
Boris Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 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 | CHIP_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 Zbarsky | a02bce4 | 2021-12-01 16:57:25 -0500 | [diff] [blame] | 56 | StatusResponse::Send(Status::InvalidAction, aExchangeContext, /* aExpectResponse = */ false); |
Boris Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 57 | } |
| 58 | return err; |
| 59 | } |
| 60 | |
| 61 | if (mState == State::kExpectingFollowingAction) |
| 62 | { |
Boris Zbarsky | 70af2c4 | 2021-12-03 02:12:35 -0500 | [diff] [blame] | 63 | 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 Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 68 | { |
| 69 | // Time is up. Spec says to send UNSUPPORTED_ACCESS. |
| 70 | ChipLogError(DataManagement, "Timeout expired: handler %p exchange " ChipLogFormatExchange, this, |
| 71 | ChipLogValueExchange(aExchangeContext)); |
Boris Zbarsky | a02bce4 | 2021-12-01 16:57:25 -0500 | [diff] [blame] | 72 | return StatusResponse::Send(Status::UnsupportedAccess, aExchangeContext, /* aExpectResponse = */ false); |
Boris Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 73 | } |
| 74 | |
| 75 | if (aPayloadHeader.HasMessageType(MsgType::InvokeCommandRequest)) |
| 76 | { |
| 77 | auto * imEngine = InteractionModelEngine::GetInstance(); |
Boris Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 78 | 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 Zbarsky | 653502d | 2021-12-02 04:01:47 -0500 | [diff] [blame] | 84 | 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 Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 92 | } |
| 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 Zbarsky | a02bce4 | 2021-12-01 16:57:25 -0500 | [diff] [blame] | 99 | return StatusResponse::Send(Status::InvalidAction, aExchangeContext, /* aExpectResponse = */ false); |
Boris Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 100 | } |
| 101 | |
| 102 | void TimedHandler::OnExchangeClosing(Messaging::ExchangeContext *) |
| 103 | { |
| 104 | InteractionModelEngine::GetInstance()->OnTimedInteractionFailed(this); |
| 105 | } |
| 106 | |
| 107 | CHIP_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 Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 114 | TimedRequestMessage::Parser parser; |
| 115 | ReturnErrorOnFailure(parser.Init(reader)); |
| 116 | |
yunhanw-google | 751d0dd | 2022-11-16 19:09:58 -0800 | [diff] [blame] | 117 | #if CHIP_CONFIG_IM_PRETTY_PRINT |
| 118 | parser.PrettyPrint(); |
Boris Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 119 | #endif |
| 120 | |
| 121 | uint16_t timeoutMs; |
| 122 | ReturnErrorOnFailure(parser.GetTimeoutMs(&timeoutMs)); |
yunhanw-google | 4394fcb | 2022-02-17 17:36:41 -0800 | [diff] [blame] | 123 | ReturnErrorOnFailure(parser.ExitContainer()); |
Boris Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 124 | |
andrei-menzopol | 57471cb | 2022-04-20 23:31:17 +0300 | [diff] [blame] | 125 | ChipLogDetail(DataManagement, "Got Timed Request with timeout %u: handler %p exchange " ChipLogFormatExchange, timeoutMs, this, |
| 126 | ChipLogValueExchange(aExchangeContext)); |
Boris Zbarsky | dc10c82 | 2021-12-02 06:55:34 -0500 | [diff] [blame] | 127 | // 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 Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 132 | auto delay = System::Clock::Milliseconds32(timeoutMs); |
Song GUO | 2f6de7b | 2022-06-02 15:34:41 +0800 | [diff] [blame] | 133 | aExchangeContext->SetResponseTimeout( |
| 134 | std::max(delay, aExchangeContext->GetSessionHandle()->ComputeRoundTripTimeout(app::kExpectedIMProcessingTime))); |
Boris Zbarsky | a02bce4 | 2021-12-01 16:57:25 -0500 | [diff] [blame] | 135 | ReturnErrorOnFailure(StatusResponse::Send(Status::Success, aExchangeContext, /* aExpectResponse = */ true)); |
Boris Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 136 | |
| 137 | // Now just wait for the client. |
| 138 | mState = State::kExpectingFollowingAction; |
| 139 | mTimeLimit = System::SystemClock().GetMonotonicTimestamp() + delay; |
Boris Zbarsky | 70af2c4 | 2021-12-03 02:12:35 -0500 | [diff] [blame] | 140 | ChipLogDetail(DataManagement, "Timed Request time limit 0x" ChipLogFormatX64 ": handler %p exchange " ChipLogFormatExchange, |
| 141 | ChipLogValueX64(mTimeLimit.count()), this, ChipLogValueExchange(aExchangeContext)); |
Boris Zbarsky | ffee2a9 | 2021-12-01 14:34:57 -0500 | [diff] [blame] | 142 | return CHIP_NO_ERROR; |
| 143 | } |
| 144 | |
| 145 | } // namespace app |
| 146 | } // namespace chip |