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/InteractionModelEngine.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 5 : CHIP_ERROR TimedHandler::OnMessageReceived(Messaging::ExchangeContext * aExchangeContext, const PayloadHeader & aPayloadHeader, 32 : System::PacketBufferHandle && aPayload) 33 : { 34 : using namespace Protocols::InteractionModel; 35 : 36 5 : 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 5 : 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 3 : VerifyOrDie(aPayloadHeader.HasMessageType(MsgType::TimedRequest)); 50 3 : mState = State::kReceivedTimedAction; 51 3 : CHIP_ERROR err = HandleTimedRequestAction(aExchangeContext, aPayloadHeader, std::move(aPayload)); 52 3 : 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 3 : return err; 59 : } 60 : 61 2 : if (mState == State::kExpectingFollowingAction) 62 : { 63 2 : System::Clock::Timestamp now = System::SystemClock().GetMonotonicTimestamp(); 64 2 : ChipLogDetail(DataManagement, 65 : "Timed following action arrived at 0x" ChipLogFormatX64 ": handler %p exchange " ChipLogFormatExchange, 66 : ChipLogValueX64(now.count()), this, ChipLogValueExchange(aExchangeContext)); 67 2 : if (now > mTimeLimit) 68 : { 69 : // Time is up. Spec says to send UNSUPPORTED_ACCESS. 70 1 : ChipLogError(DataManagement, "Timeout expired: handler %p exchange " ChipLogFormatExchange, this, 71 : ChipLogValueExchange(aExchangeContext)); 72 2 : return StatusResponse::Send(Status::UnsupportedAccess, aExchangeContext, /* aExpectResponse = */ false); 73 : } 74 : 75 1 : if (aPayloadHeader.HasMessageType(MsgType::InvokeCommandRequest)) 76 : { 77 1 : auto * imEngine = InteractionModelEngine::GetInstance(); 78 1 : ChipLogDetail(DataManagement, "Handing timed invoke to IM engine: handler %p exchange " ChipLogFormatExchange, this, 79 : ChipLogValueExchange(aExchangeContext)); 80 1 : imEngine->OnTimedInvoke(this, aExchangeContext, aPayloadHeader, std::move(aPayload)); 81 1 : return CHIP_NO_ERROR; 82 : } 83 : 84 0 : if (aPayloadHeader.HasMessageType(MsgType::WriteRequest)) 85 : { 86 0 : auto * imEngine = InteractionModelEngine::GetInstance(); 87 0 : ChipLogDetail(DataManagement, "Handing timed write to IM engine: handler %p exchange " ChipLogFormatExchange, this, 88 : ChipLogValueExchange(aExchangeContext)); 89 0 : imEngine->OnTimedWrite(this, aExchangeContext, aPayloadHeader, std::move(aPayload)); 90 0 : return CHIP_NO_ERROR; 91 : } 92 : } 93 : 94 : // Not an expected message. Send an error response. The exchange will 95 : // close when we return. 96 0 : ChipLogError(DataManagement, "Unexpected unknown message in tiemd interaction: handler %p exchange " ChipLogFormatExchange, 97 : this, ChipLogValueExchange(aExchangeContext)); 98 : 99 0 : return StatusResponse::Send(Status::InvalidAction, aExchangeContext, /* aExpectResponse = */ false); 100 : } 101 : 102 1 : void TimedHandler::OnExchangeClosing(Messaging::ExchangeContext *) 103 : { 104 1 : InteractionModelEngine::GetInstance()->OnTimedInteractionFailed(this); 105 1 : } 106 : 107 3 : CHIP_ERROR TimedHandler::HandleTimedRequestAction(Messaging::ExchangeContext * aExchangeContext, 108 : const PayloadHeader & aPayloadHeader, System::PacketBufferHandle && aPayload) 109 : { 110 : using namespace Protocols::InteractionModel; 111 : 112 3 : System::PacketBufferTLVReader reader; 113 3 : reader.Init(std::move(aPayload)); 114 3 : TimedRequestMessage::Parser parser; 115 3 : ReturnErrorOnFailure(parser.Init(reader)); 116 : 117 : #if CHIP_CONFIG_IM_PRETTY_PRINT 118 3 : parser.PrettyPrint(); 119 : #endif 120 : 121 : uint16_t timeoutMs; 122 3 : ReturnErrorOnFailure(parser.GetTimeoutMs(&timeoutMs)); 123 3 : ReturnErrorOnFailure(parser.ExitContainer()); 124 : 125 3 : ChipLogDetail(DataManagement, "Got Timed Request with timeout %u: handler %p exchange " ChipLogFormatExchange, timeoutMs, this, 126 : ChipLogValueExchange(aExchangeContext)); 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). 132 3 : auto delay = System::Clock::Milliseconds32(timeoutMs); 133 3 : aExchangeContext->SetResponseTimeout( 134 6 : std::max(delay, aExchangeContext->GetSessionHandle()->ComputeRoundTripTimeout(app::kExpectedIMProcessingTime))); 135 3 : ReturnErrorOnFailure(StatusResponse::Send(Status::Success, aExchangeContext, /* aExpectResponse = */ true)); 136 : 137 : // Now just wait for the client. 138 3 : mState = State::kExpectingFollowingAction; 139 3 : mTimeLimit = System::SystemClock().GetMonotonicTimestamp() + delay; 140 3 : ChipLogDetail(DataManagement, "Timed Request time limit 0x" ChipLogFormatX64 ": handler %p exchange " ChipLogFormatExchange, 141 : ChipLogValueX64(mTimeLimit.count()), this, ChipLogValueExchange(aExchangeContext)); 142 3 : return CHIP_NO_ERROR; 143 3 : } 144 : 145 : } // namespace app 146 : } // namespace chip