blob: 0ca5db125fb3fb704c34243ac6a7ec38db3fdb6a [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
* This file defines subscription handler for Weave
* Data Management (WDM) profile.
*
*/
#ifndef _WEAVE_DATA_MANAGEMENT_SUBSCRIPTION_HANDLER_CURRENT_H
#define _WEAVE_DATA_MANAGEMENT_SUBSCRIPTION_HANDLER_CURRENT_H
#include <Weave/Profiles/data-management/Current/WdmManagedNamespace.h>
#include <Weave/Profiles/data-management/EventLogging.h>
#include <Weave/Profiles/data-management/LoggingManagement.h>
#include <Weave/Profiles/data-management/MessageDef.h>
#include <Weave/Profiles/data-management/TraitCatalog.h>
#include <Weave/Profiles/status-report/StatusReportProfile.h>
namespace nl {
namespace Weave {
namespace Profiles {
namespace WeaveMakeManagedNamespaceIdentifier(DataManagement, kWeaveManagedNamespaceDesignation_Current) {
class SubscriptionHandler
{
public:
typedef uint8_t HandlerId;
enum
{
// Note the WDM spec says 0x7FFFFFFF, but Weave implementation can only hold timeout of much shorter
// 32-bit in milliseconds, which is about 1200 hours
kMaxTimeoutSec = 3600000,
kNoTimeout = 0,
};
struct TraitInstanceInfo
{
void Init(void)
{
this->ClearDirty();
}
bool IsDirty(void) { return mDirty; }
void SetDirty(void) { mDirty = true; }
void ClearDirty(void) { mDirty = false; }
TraitDataHandle mTraitDataHandle;
uint16_t mRequestedVersion;
bool mDirty;
};
enum EventID
{
kEvent_OnSubscribeRequestParsed = 0,
// Last chance to adjust EC, mEC is valid and can be tuned for timeout settings
// Don't change anything on the handler and don't close the EC
kEvent_OnExchangeStart = 1,
kEvent_OnSubscriptionEstablished = 2,
kEvent_OnSubscriptionTerminated = 3,
};
union InEventParam
{
void Clear(void) { memset(this, 0, sizeof(*this)); }
struct
{
TraitInstanceInfo* mTraitInstanceList;
uint16_t mNumTraitInstances;
bool mSubscribeToAllEvents;
nl::Weave::ExchangeContext * mEC;
const nl::Inet::IPPacketInfo *mPktInfo; //< A pointer to the packet information of the request
const nl::Weave::WeaveMessageInfo *mMsgInfo; //< A pointer to a WeaveMessageInfo structure containing information about the Subscribe Request message.
uint32_t mTimeoutSecMin;
uint32_t mTimeoutSecMax;
bool mIsSubscriptionIdValid;
uint64_t mSubscriptionId;
SubscriptionHandler * mHandler;
} mSubscribeRequestParsed;
struct
{
// Do not close the EC
nl::Weave::ExchangeContext * mEC;
SubscriptionHandler * mHandler;
} mExchangeStart;
struct
{
uint64_t mSubscriptionId;
SubscriptionHandler * mHandler;
} mSubscriptionEstablished;
struct
{
SubscriptionHandler * mHandler;
WEAVE_ERROR mReason;
uint32_t mStatusProfileId;
uint16_t mStatusCode;
ReferencedTLVData *mAdditionalInfoPtr;
} mSubscriptionTerminated;
};
union OutEventParam
{
void Clear(void) { memset(this, 0, sizeof(*this)); }
};
typedef void (*EventCallback) (void * const aAppState, EventID aEvent, const InEventParam & aInParam, OutEventParam & aOutParam);
static void DefaultEventHandler(EventID aEvent, const InEventParam & aInParam, OutEventParam & aOutParam);
uint64_t GetPeerNodeId(void) const;
Binding * GetBinding(void) const;
WEAVE_ERROR GetSubscriptionId (uint64_t * const apSubscriptionId);
WEAVE_ERROR AcceptSubscribeRequest(const uint32_t aLivenessTimeoutSec = kNoTimeout);
/**
* @brief This function initiates a graceful shutdown of the subscription and clean-up of the handler object. This is an asynchronous call and will notify a client of the impending shutdown
* through a SubscribeCancel/StatusReport message where relevant.
*
* Notably, this relinquishes the application's involvement in this subscription. After this call, the application will not be notified
* of any further activity on this object. Additionally, the application is not allowed to interact with this object thereafter through any of its methods.
*
* @param aReasonProfileId[in] ProfileId of the StatusCode that indicates the reason behind the termination
* @param aReasonStatusCode[in] StatusCode that indicates the reason behind the termination
*
* @retval Returns a Weave error code for informational purposes only. On any error, the object will be terminated synchronously (i.e aborted).
*
*/
WEAVE_ERROR EndSubscription(const uint32_t aReasonProfileId = nl::Weave::Profiles::kWeaveProfile_Common,
const uint16_t aReasonStatusCode = nl::Weave::Profiles::Common::kStatus_BadRequest);
/**
* @brief This function terminates a subscription immediately - this is a synchronous call. No attempt is made to notify the client of the termination, and the underlying exchange
* context if present is aborted immediately. After this call, the application will not be notified of any further activity on this object.
* Additionally, the application is not allowed to interact with this object thereafter through any of its methods.
*/
void AbortSubscription(void);
bool IsEstablishedIdle () { return (mCurrentState == kState_SubscriptionEstablished_Idle); }
bool IsActive(void) { return (mCurrentState >= kState_Subscribing_Evaluating && mCurrentState <= kState_SubscriptionEstablished_Notifying); }
bool IsAborted () { return (mCurrentState == kState_Aborted); }
bool IsFree () { return (mCurrentState == kState_Free); }
uint32_t GetMaxNotificationSize(void) const { return mMaxNotificationSize == 0 ? UINT16_MAX : mMaxNotificationSize ; }
void SetMaxNotificationSize(const uint32_t aMaxPayload);
private:
friend class SubscriptionEngine;
friend class NotificationEngine;
friend class TestSubscriptionHandler;
friend class TestTdm;
friend class TestWdm;
struct LastVendedEvent
{
uint64_t mSourceId;
uint8_t mImportance;
uint64_t mEventId;
};
enum HandlerState
{
kState_Free = 0,
kState_Subscribing_Evaluating = 1,
kState_Subscribing = 2,
kState_Subscribing_Notifying = 3,
kState_Subscribing_Responding = 4,
kState_SubscriptionEstablished_Idle = 5,
kState_SubscriptionEstablished_Notifying = 6,
kState_Canceling = 7,
kState_SubscriptionInfoValid_Begin = kState_Subscribing,
kState_SubscriptionInfoValid_End = kState_Canceling,
kState_Aborting = 9,
kState_Aborted = 10,
};
HandlerState mCurrentState;
bool IsNotifiable(void) { return (mCurrentState == kState_Subscribing || mCurrentState == kState_SubscriptionEstablished_Idle); }
bool IsSubscribing(void) { return (mCurrentState >= kState_Subscribing_Evaluating && mCurrentState <= kState_Subscribing_Responding); }
bool IsNotifying(void) { return (mCurrentState == kState_Subscribing_Notifying || mCurrentState == kState_SubscriptionEstablished_Notifying); }
// initialize once at boot up
void * mAppState;
EventCallback mEventCallback;
// initialize at incoming subscribe request
bool mIsInitiator;
int8_t mRefCount;
nl::Weave::ExchangeContext * mEC;
uint32_t mLivenessTimeoutMsec;
uint64_t mPeerNodeId;
uint64_t mSubscriptionId;
Binding * mBinding;
TraitInstanceInfo *mTraitInstanceList;
uint16_t mNumTraitInstances;
uint16_t mMaxNotificationSize;
uint32_t mCurProcessingTraitInstanceIdx;
TraitInstanceInfo *GetTraitInstanceInfoList(void) { return mTraitInstanceList; }
uint32_t GetNumTraitInstances(void) { return mNumTraitInstances; }
void OnNotifyProcessingComplete(const bool aPossibleLossOfEvent, const LastVendedEvent aLastVendedEventList[], const size_t aLastVendedEventListSize);
bool mSubscribeToAllEvents;
// TODO: WEAV-1426 in this incarnation, we do not account for event aggregation.
event_id_t mSelfVendedEvents[kImportanceType_Last - kImportanceType_First + 1];
event_id_t mLastScheduledEventId[kImportanceType_Last - kImportanceType_First + 1];
ImportanceType mCurrentImportance;
// The counter here tracks the number of event bytes offloaded to
// the subscriber. The variable is updated by the
// NotificationEngine during building the event list and it is
// read by LoggingManagement to determine if the we had
// accumulated enough bytes in events to trigger an event offload
// by triggering the NotificationEngine.
size_t mBytesOffloaded;
// Do nothing
SubscriptionHandler(void);
void _AddRef (void);
void _Release (void);
void HandleSubscriptionTerminated(WEAVE_ERROR aReason,
nl::Weave::Profiles::StatusReporting::StatusReport *aStatusReportPtr);
void MoveToState(const HandlerState aTargetState);
const char * GetStateStr() const;
WEAVE_ERROR ReplaceExchangeContext (void);
void InitExchangeContext(void);
void FlushExistingExchangeContext (const bool aAbortNow = false);
void InitWithIncomingRequest (Binding * const aBinding, const uint64_t aRandomNumber,
nl::Weave::ExchangeContext * aEC, const nl::Inet::IPPacketInfo *aPktInfo,
const nl::Weave::WeaveMessageInfo *aMsgInfo, PacketBuffer * aPayload);
WEAVE_ERROR SendNotificationRequest(PacketBuffer * aMsgBuf);
WEAVE_ERROR SendSubscribeResponse(const bool aPossibleLossOfEvent, const LastVendedEvent aLastVendedEventList[], const size_t aLastVendedEventListSize);
void TimerEventHandler (void);
WEAVE_ERROR RefreshTimer (void);
bool CheckEventUpToDate(LoggingManagement &logger);
ImportanceType FindNextImportanceForTransfer(void);
WEAVE_ERROR SetEventLogEndpoint(LoggingManagement &logger);
#if WDM_ENABLE_SUBSCRIPTION_CANCEL
WEAVE_ERROR Cancel (void);
void CancelRequestHandler (nl::Weave::ExchangeContext *aEC, const nl::Inet::IPPacketInfo *aPktInfo,
const nl::Weave::WeaveMessageInfo *aMsgInfo, PacketBuffer *aPayload);
#endif // WDM_ENABLE_SUBSCRIPTION_CANCEL
void InitAsFree(void);
inline WEAVE_ERROR ParsePathVersionEventLists(
SubscribeRequest::Parser & aRequest,
uint32_t & aRejectReasonProfileId,
uint16_t & aRejectReasonStatusCode);
inline WEAVE_ERROR ParseSubscriptionId(
SubscribeRequest::Parser & aRequest,
uint32_t & aRejectReasonProfileId,
uint16_t & aRejectReasonStatusCode,
const uint64_t aRandomNumber);
static void OnTimerCallback(System::Layer* aSystemLayer, void *aAppState, System::Error aErrorCode);
static void OnAckReceived(ExchangeContext * aEC, void * aMsgSpecificContext);
static void OnSendError (ExchangeContext *aEC, WEAVE_ERROR aErrorCode, void *aMsgSpecificContext);
static void OnResponseTimeout (nl::Weave::ExchangeContext *aEC);
static void OnMessageReceivedFromLocallyHeldExchange (nl::Weave::ExchangeContext *aEC, const nl::Inet::IPPacketInfo *aPktInfo,
const nl::Weave::WeaveMessageInfo *aMsgInfo, uint32_t aProfileId,
uint8_t aMsgType, PacketBuffer *aPayload);
};
}; // WeaveMakeManagedNamespaceIdentifier(DataManagement, kWeaveManagedNamespaceDesignation_Current)
}; // Profiles
}; // Weave
}; // nl
#endif // _WEAVE_DATA_MANAGEMENT_SUBSCRIPTION_HANDLER_CURRENT_H