-
Notifications
You must be signed in to change notification settings - Fork 2.1k
/
Copy pathTimedHandler.cpp
143 lines (125 loc) · 6.4 KB
/
TimedHandler.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/*
*
* Copyright (c) 2020 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "TimedHandler.h"
#include <app/InteractionModelTimeout.h>
#include <app/MessageDef/TimedRequestMessage.h>
#include <app/StatusResponse.h>
#include <lib/core/TLV.h>
#include <lib/support/logging/CHIPLogging.h>
#include <system/SystemClock.h>
#include <system/TLVPacketBufferBackingStore.h>
namespace chip {
namespace app {
CHIP_ERROR TimedHandler::OnMessageReceived(Messaging::ExchangeContext * aExchangeContext, const PayloadHeader & aPayloadHeader,
System::PacketBufferHandle && aPayload)
{
using namespace Protocols::InteractionModel;
if (aExchangeContext->IsGroupExchangeContext())
{
// Timed interactions are always supposed to be unicast. Nothing else
// to do here; exchange will close and we'll free ourselves.
ChipLogError(DataManagement, "Dropping Timed Request on group exchange " ChipLogFormatExchange,
ChipLogValueExchange(aExchangeContext));
return CHIP_NO_ERROR;
}
if (mState == State::kExpectingTimedAction)
{
// We were just created; our caller should have done this only if it's
// dealing with a Timed Request message.
VerifyOrDie(aPayloadHeader.HasMessageType(MsgType::TimedRequest));
mState = State::kReceivedTimedAction;
CHIP_ERROR err = HandleTimedRequestAction(aExchangeContext, aPayloadHeader, std::move(aPayload));
if (err != CHIP_NO_ERROR)
{
ChipLogError(DataManagement, "Failed to parse Timed Request action: handler %p exchange " ChipLogFormatExchange, this,
ChipLogValueExchange(aExchangeContext));
StatusResponse::Send(Status::InvalidAction, aExchangeContext, /* aExpectResponse = */ false);
}
return err;
}
if (mState == State::kExpectingFollowingAction)
{
System::Clock::Timestamp now = System::SystemClock().GetMonotonicTimestamp();
ChipLogDetail(DataManagement,
"Timed following action arrived at 0x" ChipLogFormatX64 ": handler %p exchange " ChipLogFormatExchange,
ChipLogValueX64(now.count()), this, ChipLogValueExchange(aExchangeContext));
if (now > mTimeLimit)
{
ChipLogError(DataManagement, "Timeout expired: handler %p exchange " ChipLogFormatExchange, this,
ChipLogValueExchange(aExchangeContext));
return StatusResponse::Send(Status::Timeout, aExchangeContext, /* aExpectResponse = */ false);
}
if (aPayloadHeader.HasMessageType(MsgType::InvokeCommandRequest))
{
ChipLogDetail(DataManagement, "Handing timed invoke to IM engine: handler %p exchange " ChipLogFormatExchange, this,
ChipLogValueExchange(aExchangeContext));
mDelegate->OnTimedInvoke(this, aExchangeContext, aPayloadHeader, std::move(aPayload));
return CHIP_NO_ERROR;
}
if (aPayloadHeader.HasMessageType(MsgType::WriteRequest))
{
ChipLogDetail(DataManagement, "Handing timed write to IM engine: handler %p exchange " ChipLogFormatExchange, this,
ChipLogValueExchange(aExchangeContext));
mDelegate->OnTimedWrite(this, aExchangeContext, aPayloadHeader, std::move(aPayload));
return CHIP_NO_ERROR;
}
}
// Not an expected message. Send an error response. The exchange will
// close when we return.
ChipLogError(DataManagement, "Unexpected unknown message in tiemd interaction: handler %p exchange " ChipLogFormatExchange,
this, ChipLogValueExchange(aExchangeContext));
return StatusResponse::Send(Status::InvalidAction, aExchangeContext, /* aExpectResponse = */ false);
}
void TimedHandler::OnExchangeClosing(Messaging::ExchangeContext *)
{
mDelegate->OnTimedInteractionFailed(this);
}
CHIP_ERROR TimedHandler::HandleTimedRequestAction(Messaging::ExchangeContext * aExchangeContext,
const PayloadHeader & aPayloadHeader, System::PacketBufferHandle && aPayload)
{
using namespace Protocols::InteractionModel;
System::PacketBufferTLVReader reader;
reader.Init(std::move(aPayload));
TimedRequestMessage::Parser parser;
ReturnErrorOnFailure(parser.Init(reader));
#if CHIP_CONFIG_IM_PRETTY_PRINT
parser.PrettyPrint();
#endif
uint16_t timeoutMs;
ReturnErrorOnFailure(parser.GetTimeoutMs(&timeoutMs));
ReturnErrorOnFailure(parser.ExitContainer());
ChipLogDetail(DataManagement, "Got Timed Request with timeout %u: handler %p exchange " ChipLogFormatExchange, timeoutMs, this,
ChipLogValueExchange(aExchangeContext));
// Use at least our default IM timeout, because if we close our exchange as
// soon as we know the delay has passed we won't be able to send the
// UNSUPPORTED_ACCESS status code the spec tells us to send (and in fact
// will send nothing and the other side will have to time out to realize
// it's missed its window).
auto delay = System::Clock::Milliseconds32(timeoutMs);
aExchangeContext->SetResponseTimeout(
std::max(delay, aExchangeContext->GetSessionHandle()->ComputeRoundTripTimeout(app::kExpectedIMProcessingTime)));
ReturnErrorOnFailure(StatusResponse::Send(Status::Success, aExchangeContext, /* aExpectResponse = */ true));
// Now just wait for the client.
mState = State::kExpectingFollowingAction;
mTimeLimit = System::SystemClock().GetMonotonicTimestamp() + delay;
ChipLogDetail(DataManagement, "Timed Request time limit 0x" ChipLogFormatX64 ": handler %p exchange " ChipLogFormatExchange,
ChipLogValueX64(mTimeLimit.count()), this, ChipLogValueExchange(aExchangeContext));
return CHIP_NO_ERROR;
}
} // namespace app
} // namespace chip