blob: 814ce4344a589bacdef7eddc28fdcd147e4b2e2a [file] [log] [blame]
/*
*
* Copyright (c) 2016-2017 Nest Labs, Inc.
* 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.
*/
/**
* @file
*
* @brief
* Definitions for the ProtocolEngine class.
*
* This file defines common methods and callbacks for the WDM
* ProtocoleEngine, most applicable to both client and publisher. See
* the document, "Nest Weave-Data Management Protocol" document for a
* complete description.
*
* ProtocolEngine is not, in itself, part of the publish interface to
* WDM but it provides the basis of that interface.
*/
#ifndef _WEAVE_DATA_MANAGEMENT_PROTOCOL_ENGINE_LEGACY_H
#define _WEAVE_DATA_MANAGEMENT_PROTOCOL_ENGINE_LEGACY_H
#include <Weave/Profiles/data-management/Legacy/WdmManagedNamespace.h>
#include <SystemLayer/SystemStats.h>
namespace nl {
namespace Weave {
namespace Profiles {
namespace WeaveMakeManagedNamespaceIdentifier(DataManagement, kWeaveManagedNamespaceDesignation_Legacy) {
/*
* and various entities need to be able to send a status report
*/
WEAVE_ERROR SendStatusReport(ExchangeContext *aExchangeCtx, StatusReport &aStatus);
/**
* @class ProtocolEngine
*
* @brief
* The WDM protocol engine class.
*
* A data management entity, client or publisher, has a protocol
* engine component and a data manager component. This abstract
* class represents the common features of the protocol engine.
*/
class ProtocolEngine
{
friend class Binding;
friend class ClientNotifier;
friend class DMClient;
friend class DMPublisher;
public:
/**
* @class Transaction
*
* @brief
* A protocol transaction containing application state.
*
* Both client and publisher define transactions that may take
* a while to complete and require multiple steps,
* e.g. connection establishment, data marshaling etc. These
* maintain necessary application state for the duration.
*
* Note that transactions, even though they are made public
* for access reasons, are really only used in the context of
* the protocol engine and are not part of the public
* interface to WDM in any significant sense.
*/
class DMTransaction
{
friend class ProtocolEngine;
friend class DMClient;
friend class DMPublisher;
public:
void OnMsgReceived(const uint64_t &aResponderId, uint32_t aProfileId, uint8_t aMsgType, PacketBuffer *aMsg);
/*
* subclass-defined "special sauce"
*/
virtual WEAVE_ERROR SendRequest(PacketBuffer *aBuffer, uint16_t aSendFlags) = 0;
virtual WEAVE_ERROR OnResponseReceived(const uint64_t &aResponderId, uint8_t aMsgType, PacketBuffer *aMsg);
virtual void OnResponseTimeout(const uint64_t &aResponderid);
virtual WEAVE_ERROR OnStatusReceived(const uint64_t &aResponderId, StatusReport &aStatus) = 0;
protected:
WEAVE_ERROR Init(ProtocolEngine *aEngine, uint16_t aTxnId, uint32_t aTimeout);
virtual void Free(void);
bool IsFree(void);
WEAVE_ERROR Start(uint8_t aTransport);
void Finish(void);
WEAVE_ERROR Finalize(void);
void OnError(const uint64_t &aResponderId, WEAVE_ERROR aError);
uint16_t mTxnId;
ProtocolEngine *mEngine;
uint32_t mTimeout;
ExchangeContext *mExchangeCtx;
#if WEAVE_CONFIG_WDM_ALLOW_CLIENT_LEGACY_MESSAGE_TYPES
/*
* this is declared here and accessible only from friend
* classes by which it may be used to select the old-style
* message types.
*/
bool mUseLegacyMsgType;
#endif // WEAVE_CONFIG_WDM_ALLOW_CLIENT_LEGACY_MESSAGE_TYPES
};
ProtocolEngine(void);
virtual ~ProtocolEngine(void);
virtual WEAVE_ERROR Init(WeaveExchangeManager *aExchangeMgr);
virtual WEAVE_ERROR Init(WeaveExchangeManager *aExchangeMgr, uint32_t aResponseTimeout);
protected:
virtual void Finalize(void);
void Clear(void);
/*
* the procedure for sending a status response is the same all over
*/
inline WEAVE_ERROR StatusResponse(ExchangeContext *aExchangeCtx, StatusReport &aStatus)
{
return SendStatusReport(aExchangeCtx, aStatus);
}
public:
/*
* the public portion of the ProtocolEngine API has to do with
* the care adn feeding of the binding table.
*/
WEAVE_ERROR BindRequest(const uint64_t &aPeerNodeId, uint8_t aTransport);
/**
* @brief
* Bind to a known peer using the default transport.
*
* @param [in] aPeerNodeId A reference to the 64-bit
* node ID of the peer entity
* that is the binding target.
*
* @return #WEAVE_NO_ERROR On success. Otherwise return a
* #WEAVE_ERROR reflecting the failure of the bind operation.
*/
inline WEAVE_ERROR BindRequest(const uint64_t &aPeerNodeId)
{
#if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING
return BindRequest(aPeerNodeId, kTransport_WRMP);
#else
return BindRequest(aPeerNodeId, kTransport_TCP);
#endif
};
#if WEAVE_CONFIG_ENABLE_SERVICE_DIRECTORY
WEAVE_ERROR BindRequest(nl::Weave::Profiles::ServiceDirectory::WeaveServiceManager *aServiceMgr, WeaveAuthMode aAuthMode);
#endif
WEAVE_ERROR BindRequest(WeaveConnection *aConnection);
virtual WEAVE_ERROR BindConfirm(Binding *aBinding);
virtual WEAVE_ERROR BindConfirm(Binding *aBinding, StatusReport &aReport);
void UnbindRequest(const uint64_t &aPeerNodeId);
void UnbindRequest(const uint64_t &aPeerNodeId, WEAVE_ERROR aErr);
virtual void IncompleteIndication(Binding *aBinding, StatusReport &aReport);
/**
* @brief
* Handle an indication that a binding has become
* incomplete.
*
* Higher layers that want to be informed of binding failure
* should use this method, which simply passes the peer ID
* along with a status report. In fact, since this method is
* virtual void, any DMClient or DMPublisher subclass must
* provide an implementation.
*
* @param [in] aPeerNodeId A reference to the 64-bit
* ID of the peer node or
* service endpoint that is
* that target of the failed
* binding.
*
* @param [in] aReport A reference to a StatusReport
* object detailing the
* reason for failure.
*/
virtual void IncompleteIndication(const uint64_t &aPeerNodeId, StatusReport &aReport) = 0;
protected:
Binding *FromExchangeCtx(ExchangeContext *aExchangeCtx);
Binding *GetBinding(const uint64_t &aPeerNodeId);
Binding *NewBinding(void);
void ClearBindingTable(void);
void FinalizeBindingTable(void);
/*
* the protocol engine has to keep a queue of transactions
* pending the completion of a binding, including its default
* binding. these methods manage it and transactions generally.
*/
WEAVE_ERROR StartTransaction(DMTransaction *aTransaction, Binding *aBinding);
WEAVE_ERROR StartTransaction(DMTransaction *aTransaction)
{
return StartTransaction(aTransaction, &mBindingTable[kDefaultBindingTableIndex]);
};
WEAVE_ERROR EnqueueTransaction(DMTransaction *aTransaction, Binding *aBinding);
inline WEAVE_ERROR EnqueueTransaction(DMTransaction *aTransaction)
{
return EnqueueTransaction(aTransaction, &mBindingTable[kDefaultBindingTableIndex]);
};
void DequeueTransaction(DMTransaction *aTransaction);
void FinalizeTransactions(Binding *aBinding);
bool FailTransactions(Binding *aBinding, StatusReport &aReport);
void ClearTransactionTable(void);
void FinalizeTransactionTable(void);
// data members
WeaveExchangeManager *mExchangeMgr;
uint32_t mResponseTimeout; // milliseconds, 0 == "don't wait"
/**
* The ProtocolEngine has a binding table that, if the engine
* is going to be responsible for anything beyond simply
* receiving broadcast notifications, probably needs to
* contain at least one entry. Bindings are generally indexed
* by node ID. What this means is that each engine can only
* have a single binding to a given service endpoint.
*
* The WDM specification has this notion of "default binding" which is
* the place messages go if no explicit destination is
* supplied. This will mostly be used in very simple devices
* with a single binding or a small number of bindings and,
* for other purposes, will just be the first binding formed.
*/
Binding mBindingTable[kBindingTableSize];
/*
* the ProtocolEngine object also keeps track of at least one
* pending transaction, which may be awaiting the completion
* of a binding. when the binding completes, all the pending
* transactions that depend on it are started, and when the
* binding fails they are all canceled.
*/
struct TransactionTableEntry
{
inline void Init(DMTransaction *aTransaction, Binding *aBinding)
{
mTransaction = aTransaction;
mBinding = aBinding;
};
inline void Free(void)
{
mTransaction = NULL;
mBinding = NULL;
SYSTEM_STATS_DECREMENT(nl::Weave::System::Stats::kWDMClient_NumTransactions);
};
inline bool IsFree(void)
{
return !mTransaction;
};
void Finalize(void);
void Fail(const uint64_t &aPeerId, StatusReport &aReport);
DMTransaction *mTransaction;
Binding *mBinding;
};
TransactionTableEntry mTransactionTable[kTransactionTableSize];
};
}; // WeaveMakeManagedNamespaceIdentifier(DataManagement, kWeaveManagedNamespaceDesignation_Legacy)
}; // Profiles
}; // Weave
}; // nl
#endif // _WEAVE_DATA_MANAGEMENT_PROTOCOL_ENGINE_LEGACY_H