blob: fe4e0a4455092b7ad632e342c68038f0a4c613cd [file] [log] [blame]
/*
*
* Copyright (c) 2020-2021 Project CHIP Authors
*
* 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.
*/
/**
* @file
* This file defines the classes corresponding to CHIP Exchange Context.
*
*/
#pragma once
#include <lib/core/ReferenceCounted.h>
#include <messaging/ExchangeACL.h>
#include <messaging/ExchangeDelegate.h>
#include <messaging/Flags.h>
#include <messaging/ReliableMessageContext.h>
#include <protocols/Protocols.h>
#include <support/BitFlags.h>
#include <support/DLLUtil.h>
#include <system/SystemTimer.h>
#include <transport/SecureSessionMgr.h>
namespace chip {
namespace Messaging {
class ExchangeManager;
class ExchangeContext;
class ExchangeMessageDispatch;
class ExchangeContextDeletor
{
public:
static void Release(ExchangeContext * obj);
};
/**
* @brief
* This class represents an ongoing conversation (ExchangeContext) between two or more nodes.
* It defines methods for encoding and communicating CHIP messages within an ExchangeContext
* over various transport mechanisms, for example, TCP, UDP, or CHIP Reliable Messaging.
*/
class DLL_EXPORT ExchangeContext : public ReliableMessageContext, public ReferenceCounted<ExchangeContext, ExchangeContextDeletor>
{
friend class ExchangeManager;
friend class ExchangeContextDeletor;
public:
typedef uint32_t Timeout; // Type used to express the timeout in this ExchangeContext, in milliseconds
ExchangeContext(ExchangeManager * em, uint16_t ExchangeId, SecureSessionHandle session, bool Initiator,
ExchangeDelegateBase * delegate);
~ExchangeContext();
/**
* Determine whether the context is the initiator of the exchange.
*
* @return Returns 'true' if it is the initiator, else 'false'.
*/
bool IsInitiator() const;
/**
* Send a CHIP message on this exchange.
*
* @param[in] protocolId The protocol identifier of the CHIP message to be sent.
*
* @param[in] msgType The message type of the corresponding protocol.
*
* @param[in] msgPayload A handle to the packet buffer holding the CHIP message.
*
* @param[in] sendFlags Flags set by the application for the CHIP message being sent.
*
* @retval #CHIP_ERROR_INVALID_ARGUMENT if an invalid argument was passed to this SendMessage API.
* @retval #CHIP_ERROR_WRONG_MSG_VERSION_FOR_EXCHANGE if there is a mismatch in the specific send operation and the
* CHIP message protocol version that is supported.
* @retval #CHIP_ERROR_NOT_CONNECTED if the context was associated with a connection that is now
* closed.
* @retval #CHIP_ERROR_INCORRECT_STATE if the state of the exchange context is incorrect.
* @retval #CHIP_NO_ERROR if the CHIP layer successfully sent the message down to the
* network layer.
*/
CHIP_ERROR SendMessage(Protocols::Id protocolId, uint8_t msgType, System::PacketBufferHandle msgPayload,
const SendFlags & sendFlags = SendFlags(SendMessageFlags::kNone));
/**
* A strongly-message-typed version of SendMessage.
*/
template <typename MessageType, typename = std::enable_if_t<std::is_enum<MessageType>::value>>
CHIP_ERROR SendMessage(MessageType msgType, System::PacketBufferHandle && msgPayload,
const SendFlags & sendFlags = SendFlags(SendMessageFlags::kNone))
{
static_assert(std::is_same<std::underlying_type_t<MessageType>, uint8_t>::value, "Enum is wrong size; cast is not safe");
return SendMessage(Protocols::MessageTypeTraits<MessageType>::ProtocolId(), static_cast<uint8_t>(msgType),
std::move(msgPayload), sendFlags);
}
/**
* Handle a received CHIP message on this exchange.
*
* @param[in] packetHeader A reference to the PacketHeader object.
*
* @param[in] payloadHeader A reference to the PayloadHeader object.
*
* @param[in] peerAddress The address of the sender
*
* @param[in] msgBuf A handle to the packet buffer holding the CHIP message.
*
* @retval #CHIP_ERROR_INVALID_ARGUMENT if an invalid argument was passed to this HandleMessage API.
* @retval #CHIP_ERROR_INCORRECT_STATE if the state of the exchange context is incorrect.
* @retval #CHIP_NO_ERROR if the CHIP layer successfully delivered the message up to the
* protocol layer.
*/
CHIP_ERROR HandleMessage(const PacketHeader & packetHeader, const PayloadHeader & payloadHeader,
const Transport::PeerAddress & peerAddress, System::PacketBufferHandle msgBuf);
ExchangeDelegateBase * GetDelegate() const { return mDelegate; }
void SetDelegate(ExchangeDelegateBase * delegate) { mDelegate = delegate; }
ExchangeManager * GetExchangeMgr() const { return mExchangeMgr; }
ReliableMessageContext * GetReliableMessageContext() { return static_cast<ReliableMessageContext *>(this); };
ExchangeMessageDispatch * GetMessageDispatch();
ExchangeACL * GetExchangeACL(Transport::AdminPairingTable & table)
{
if (mExchangeACL == nullptr)
{
Transport::AdminPairingInfo * admin = table.FindAdminWithId(mSecureSession.GetAdminId());
if (admin != nullptr)
{
mExchangeACL = chip::Platform::New<CASEExchangeACL>(admin);
}
}
return mExchangeACL;
}
SecureSessionHandle GetSecureSession() { return mSecureSession; }
uint16_t GetExchangeId() const { return mExchangeId; }
/*
* In order to use reference counting (see refCount below) we use a hold/free paradigm where users of the exchange
* can hold onto it while it's out of their direct control to make sure it isn't closed before everyone's ready.
* A customized version of reference counting is used since there are some extra stuff to do within Release.
*/
void Close();
void Abort();
void SetResponseTimeout(Timeout timeout);
private:
Timeout mResponseTimeout; // Maximum time to wait for response (in milliseconds); 0 disables response timeout.
ExchangeDelegateBase * mDelegate = nullptr;
ExchangeManager * mExchangeMgr = nullptr;
ExchangeACL * mExchangeACL = nullptr;
SecureSessionHandle mSecureSession; // The connection state
uint16_t mExchangeId; // Assigned exchange ID.
/**
* Determine whether a response is currently expected for a message that was sent over
* this exchange. While this is true, attempts to send other messages that expect a response
* will fail.
*
* @return Returns 'true' if response expected, else 'false'.
*/
bool IsResponseExpected() const;
/**
* Track whether we are now expecting a response to a message sent via this exchange (because that
* message had the kExpectResponse flag set in its sendFlags).
*
* @param[in] inResponseExpected A Boolean indicating whether (true) or not
* (false) a response is currently expected on this
* exchange.
*/
void SetResponseExpected(bool inResponseExpected);
/**
* Search for an existing exchange that the message applies to.
*
* @param[in] session The secure session of the received message.
*
* @param[in] packetHeader A reference to the PacketHeader object.
*
* @param[in] payloadHeader A reference to the PayloadHeader object.
*
* @retval true If a match is found.
* @retval false If a match is not found.
*/
bool MatchExchange(SecureSessionHandle session, const PacketHeader & packetHeader, const PayloadHeader & payloadHeader);
CHIP_ERROR StartResponseTimer();
void CancelResponseTimer();
static void HandleResponseTimeout(System::Layer * aSystemLayer, void * aAppState, System::Error aError);
void DoClose(bool clearRetransTable);
};
} // namespace Messaging
} // namespace chip