blob: c067cad762268673969d3c11788343d3c5b312ba [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 implements the Weave Data Management mock subscription responder.
*
*/
#define WEAVE_CONFIG_ENABLE_FUNCT_ERROR_LOGGING 1
#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif // __STDC_FORMAT_MACROS
#include <inttypes.h>
// Note that the choice of namespace alias must be made up front for each and every compile unit
// This is because many include paths could set the default alias to unintended target.
#include <Weave/Profiles/bulk-data-transfer/Development/BDXManagedNamespace.hpp>
#include <Weave/Profiles/data-management/Current/WdmManagedNamespace.h>
#include <Weave/Core/WeaveCore.h>
#include <Weave/Core/WeaveTLVDebug.hpp>
#include <Weave/Profiles/WeaveProfiles.h>
#include <Weave/Profiles/common/CommonProfile.h>
#include <Weave/Profiles/data-management/DataManagement.h>
#include <Weave/Profiles/status-report/StatusReportProfile.h>
#include <Weave/Profiles/security/ApplicationKeysTraitDataSink.h>
#include <Weave/Support/CodeUtils.h>
#include <Weave/Support/TimeUtils.h>
#include <Weave/Support/ASN1.h>
#include "MockWdmTestVerifier.h"
#include "MockWdmSubscriptionResponder.h"
#include "MockSinkTraits.h"
#include "MockSourceTraits.h"
#include "MockWdmTestVerifier.h"
#include "TestPlatformTime.h"
using nl::Weave::System::PacketBuffer;
#if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING
using namespace nl::Weave::TLV;
using namespace nl::Weave::Profiles;
using namespace nl::Weave::Profiles::DataManagement;
using namespace Schema::Weave::Trait::Auth::ApplicationKeysTrait;
const nl::Weave::ExchangeContext::Timeout kResponseTimeoutMsec = 15000;
const nl::Weave::ExchangeContext::Timeout kWRMPActiveRetransTimeoutMsec = 3000;
const nl::Weave::ExchangeContext::Timeout kWRMPInitialRetransTimeoutMsec = 3000;
const uint16_t kWRMPMaxRetrans = 3;
const uint16_t kWRMPAckTimeoutMsec = 200;
const nl::Weave::Profiles::Time::timesync_t kCommandTimeoutMicroSecs = 30*nl::kMicrosecondsPerSecond;
static int gNumDataChangeBeforeCancellation;
static int gFinalStatus;
static SubscriptionHandler *gSubscriptionHandler = NULL;
static int gTimeBetweenDataChangeMsec = 0;
static bool gEnableDataFlip = true;
static nl::Weave::Binding * gBinding = NULL;
static bool gClearDataSink = false;
static bool gCleanStatus = true;
static nl::Weave::WRMPConfig gWRMPConfig = { kWRMPInitialRetransTimeoutMsec, kWRMPActiveRetransTimeoutMsec, kWRMPAckTimeoutMsec, kWRMPMaxRetrans };
nl::Weave::Profiles::DataManagement::SubscriptionEngine * nl::Weave::Profiles::DataManagement::SubscriptionEngine::GetInstance()
{
static nl::Weave::Profiles::DataManagement::SubscriptionEngine gWdmSubscriptionEngine;
return &gWdmSubscriptionEngine;
}
struct VersionNode
{
uint64_t versionInfo;
VersionNode * next;
};
class WdmResponderState
{
public:
int mDataflipCount;
int mClientStateCount;
int mPublisherStateCount;
void init(void)
{
mDataflipCount = 1;
mClientStateCount = 1;
mPublisherStateCount = 1;
}
};
static WdmResponderState gResponderState;
class MockWdmSubscriptionResponderImpl: public MockWdmSubscriptionResponder
{
public:
MockWdmSubscriptionResponderImpl ();
virtual WEAVE_ERROR Init (nl::Weave::WeaveExchangeManager *aExchangeMgr, const bool aMutualSubscription,
const char * const aTestCaseId, const char * const aNumDataChangeBeforeCancellation,
const char * const aFinalStatus, const char * const aTimeBetweenDataChangeMsec, const bool aEnableDataFlip,
const char * const aTimeBetweenLivenessCheckSec);
void PrintVersionsLog();
virtual void ClearDataSinkState(void);
private:
nl::Weave::WeaveExchangeManager *mExchangeMgr;
static void ClearDataSinkIterator(void *aTraitInstance, TraitDataHandle aHandle, void *aContext);
bool mIsMutualSubscription;
int mTestCaseId;
// publisher side
uint32_t mTimeBetweenLivenessCheckSec;
SingleResourceSourceTraitCatalog mSourceCatalog;
SingleResourceSourceTraitCatalog::CatalogItem mSourceCatalogStore[6];
// source traits
LocaleSettingsTraitDataSource mLocaleSettingsDataSource;
TestATraitDataSource mTestADataSource0;
TestATraitDataSource mTestADataSource1;
TestBTraitDataSource mTestBDataSource;
TestBLargeTraitDataSource mTestBLargeDataSource;
BoltLockSettingTraitDataSource mBoltLockSettingDataSource;
ApplicationKeysTraitDataSource mApplicationKeysTraitDataSource;
static void EngineEventCallback (void * const aAppState, SubscriptionEngine::EventID aEvent,
const SubscriptionEngine::InEventParam & aInParam, SubscriptionEngine::OutEventParam & aOutParam);
static void PublisherEventCallback (void * const aAppState,
SubscriptionHandler::EventID aEvent, const SubscriptionHandler::InEventParam & aInParam, SubscriptionHandler::OutEventParam & aOutParam);
// client side
TestATraitDataSink mTestADataSink0;
TestATraitDataSink mTestADataSink1;
TestBTraitDataSink mTestBDataSink;
LocaleCapabilitiesTraitDataSink mLocaleCapabilitiesDataSink;
SingleResourceSinkTraitCatalog mSinkCatalog;
SingleResourceSinkTraitCatalog::CatalogItem mSinkCatalogStore[4];
nl::Weave::Profiles::DataManagement_Current::TraitSchemaEngine::IDataSourceDelegate* mSinkAddressList[4];
enum
{
kTestADataSink0Index = 0,
kTestADataSink1Index,
kTestBDataSinkIndex,
kLocaleCapabilitiesTraitSinkIndex,
kTestATraitSource0Index,
kTestATraitSource1Index,
kTestBTraitSourceIndex,
kTestBLargeTraitSourceIndex,
kLocaleSettingsTraitSourceIndex,
kBoltLockSettingTraitSourceIndex,
kApplicationKeysTraitSourceIndex,
kNumTraitHandles,
};
enum
{
kClientCancel = 0,
kPublisherCancel,
kClientAbort,
kPublisherAbort,
kIdle,
};
TraitDataHandle mTraitHandleSet[kNumTraitHandles];
enum
{
// subscribe LocaleSettings, TestA(two instances) and TestB traits in initiator
// publish TestA(two instances) and TestB traits in initiator
kTestCase_TestTrait = 1,
// subscribe Locale Setting, ApplicationKeys traits in initiator
// publish Locale Capabilities traits in responder
kTestCase_IntegrationTrait = 2,
//Reject Incoming subscribe request
kTestCase_RejectIncomingSubscribeRequest = 3,
// subscribe oversize TestB, TestA(two instances) traits and LocaleSettings in initiator
// publish TestA(two instances) and oversize TestB traits in initiator
kTestCase_TestOversizeTrait1 = 4,
// subscribe oversize LocaleSettings, TestB, and TestA(two instances) traits in initiator
// publish TestA(two instances) and oversize TestB traits in initiator
kTestCase_TestOversizeTrait2 = 5,
kTestCase_CompatibleVersionedRequest = 6,
kTestCase_ForwardCompatibleVersionedRequest = 7,
kTestCase_IncompatibleVersionedRequest = 8,
kTestCase_IncompatibleVersionedCommandRequest = 9
};
enum
{
kMonitorCurrentStateCnt = 160,
kMonitorCurrentStateInterval = 120 //msec
};
TraitPath mTraitPaths[4];
VersionedTraitPath mVersionedTraitPaths[4];
uint32_t mNumPaths;
VersionNode mTraitVersionSet[kNumTraitHandles];
SubscriptionClient * mSubscriptionClient;
void AddNewVersion (int aTraitDataSinkIndex);
void DumpClientTraitChecksum(int TraitDataSinkIndex);
void DumpClientTraits(void);
void DumpPublisherTraitChecksum(int TraitDataSounceIndex);
void DumpPublisherTraits(void);
static void ClientEventCallback (void * const aAppState, SubscriptionClient::EventID aEvent,
const SubscriptionClient::InEventParam & aInParam, SubscriptionClient::OutEventParam & aOutParam);
static void HandleDataFlipTimeout(nl::Weave::System::Layer* aSystemLayer, void *aAppState, ::nl::Weave::System::Error aErr);
static void HandleClientComplete(void *aAppState);
static void HandleClientRelease(void *aAppState);
static void HandlePublisherComplete();
static void HandlePublisherRelease();
static void MonitorPublisherCurrentState (nl::Weave::System::Layer* aSystemLayer, void *aAppState, INET_ERROR aErr);
static void MonitorClientCurrentState (nl::Weave::System::Layer* aSystemLayer, void *aAppState, INET_ERROR aErr);
enum CustomCommandState
{
kCmdState_Idle = 0, //< No active command
kCmdState_Requesting = 1, //< Command has been sent but we haven't heard anything back
kCmdState_Operating = 2, //< We have received In-Progress message but are still waiting for response
};
CustomCommandState mCmdState;
nl::Weave::ExchangeContext * mEcCommand;
void Command_Send (void);
void Command_End (const bool aAbort = false);
static void OnMessageReceivedForCustomCommand (nl::Weave::ExchangeContext *aEC, const nl::Inet::IPPacketInfo *aPktInfo,
const nl::Weave::WeaveMessageInfo *aMsgInfo, uint32_t aProfileId,
uint8_t aMsgType, PacketBuffer *aPayload);
static void HandleCustomCommandTimeout(nl::Weave::System::Layer* aSystemLayer, void *aAppState, ::nl::Weave::System::Error aErr);
};
static MockWdmSubscriptionResponderImpl gWdmSubscriptionResponder;
MockWdmSubscriptionResponder * MockWdmSubscriptionResponder::GetInstance ()
{
return &gWdmSubscriptionResponder;
}
MockWdmSubscriptionResponderImpl::MockWdmSubscriptionResponderImpl() :
mTimeBetweenLivenessCheckSec(30),
mSourceCatalog(ResourceIdentifier(ResourceIdentifier::SELF_NODE_ID), mSourceCatalogStore, sizeof(mSourceCatalogStore) / sizeof(mSourceCatalogStore[0])),
mSinkCatalog(ResourceIdentifier(ResourceIdentifier::SELF_NODE_ID), mSinkCatalogStore, sizeof(mSinkCatalogStore) / sizeof(mSinkCatalogStore[0])),
mCmdState(kCmdState_Idle),
mEcCommand(NULL)
{
}
WEAVE_ERROR MockWdmSubscriptionResponderImpl::Init (nl::Weave::WeaveExchangeManager *aExchangeMgr,
const bool aMutualSubscription, const char * const aTestCaseId, const char * const aNumDataChangeBeforeCancellation,
const char * const aFinalStatus, const char * const aTimeBetweenDataChangeMsec, const bool aEnableDataFlip,
const char * const aTimeBetweenLivenessCheckSec)
{
gResponderState.init();
WEAVE_ERROR err = WEAVE_NO_ERROR;
WeaveLogDetail(DataManagement, "Test Case ID: %s", (aTestCaseId == NULL) ? "NULL" : aTestCaseId);
if (NULL != aNumDataChangeBeforeCancellation)
{
gNumDataChangeBeforeCancellation = atoi(aNumDataChangeBeforeCancellation);
if (gNumDataChangeBeforeCancellation < -1)
{
gNumDataChangeBeforeCancellation = -1;
}
}
else
{
gNumDataChangeBeforeCancellation = -1;
}
if (NULL != aFinalStatus)
{
gFinalStatus = atoi(aFinalStatus);
}
else
{
gFinalStatus = 1;
}
if (NULL != aTestCaseId)
{
mTestCaseId = atoi(aTestCaseId);
}
else
{
mTestCaseId = kTestCase_TestTrait;
}
if (NULL != aTimeBetweenDataChangeMsec)
{
gTimeBetweenDataChangeMsec = atoi(aTimeBetweenDataChangeMsec);
}
else
{
gTimeBetweenDataChangeMsec = 15000;
}
gEnableDataFlip = aEnableDataFlip;
if (NULL != aTimeBetweenLivenessCheckSec)
{
mTimeBetweenLivenessCheckSec = atoi(aTimeBetweenLivenessCheckSec);
}
else
{
mTimeBetweenLivenessCheckSec = 30;
}
mTestADataSource0.mTraitTestSet = 0;
mTestADataSource1.mTraitTestSet = 1;
mSinkCatalog.Add(1, &mTestADataSink0, mTraitHandleSet[kTestADataSink0Index]);
mSinkCatalog.Add(2, &mTestADataSink1, mTraitHandleSet[kTestADataSink1Index]);
mSinkCatalog.Add(1, &mTestBDataSink, mTraitHandleSet[kTestBDataSinkIndex]);
mSinkCatalog.Add(0, &mLocaleCapabilitiesDataSink, mTraitHandleSet[kLocaleCapabilitiesTraitSinkIndex]);
mSourceCatalog.Add(0, &mTestADataSource0, mTraitHandleSet[kTestATraitSource0Index]);
mSourceCatalog.Add(1, &mTestADataSource1, mTraitHandleSet[kTestATraitSource1Index]);
switch (mTestCaseId)
{
case kTestCase_TestOversizeTrait1:
case kTestCase_TestOversizeTrait2:
mSourceCatalog.Add(0, &mTestBLargeDataSource, mTraitHandleSet[kTestBLargeTraitSourceIndex]);
break;
default:
mSourceCatalog.Add(0, &mTestBDataSource, mTraitHandleSet[kTestBTraitSourceIndex]);
break;
}
mSourceCatalog.Add(0, &mLocaleSettingsDataSource, mTraitHandleSet[kLocaleSettingsTraitSourceIndex]);
mSourceCatalog.Add(0, &mBoltLockSettingDataSource, mTraitHandleSet[kBoltLockSettingTraitSourceIndex]);
mSourceCatalog.Add(0, &mApplicationKeysTraitDataSource, mTraitHandleSet[kApplicationKeysTraitSourceIndex]);
switch (mTestCaseId)
{
case kTestCase_IntegrationTrait:
WeaveLogDetail(DataManagement, "kTestCase_IntegrationTrait");
break;
case kTestCase_RejectIncomingSubscribeRequest:
WeaveLogDetail(DataManagement, "kTestCase_RejectIncomingSubscribeRequest");
break;
case kTestCase_TestTrait:
WeaveLogDetail(DataManagement, "kTestCase_TestTrait");
break;
case kTestCase_TestOversizeTrait1:
case kTestCase_TestOversizeTrait2:
WeaveLogDetail(DataManagement, "kTestCase_TestOversizeTrait %d", mTestCaseId);
break;
case kTestCase_CompatibleVersionedRequest:
WeaveLogDetail(DataManagement, "kTestCase_CompatibleVersionedRequest");
break;
case kTestCase_ForwardCompatibleVersionedRequest:
WeaveLogDetail(DataManagement, "kTestCase_ForwardCompatibleVersionedRequest");
break;
case kTestCase_IncompatibleVersionedRequest:
WeaveLogDetail(DataManagement, "kTestCase_IncompatibleVersionedRequest");
break;
case kTestCase_IncompatibleVersionedCommandRequest:
WeaveLogDetail(DataManagement, "kTestCase_IncompatibleVersionedCommandRequest");
break;
default:
WeaveLogDetail(DataManagement, "kTestCase_TestTrait");
break;
}
mIsMutualSubscription = aMutualSubscription;
mSubscriptionClient = NULL;
mExchangeMgr = aExchangeMgr;
err = SubscriptionEngine::GetInstance()->Init(mExchangeMgr, this, EngineEventCallback);
SuccessOrExit(err);
err = SubscriptionEngine::GetInstance()->EnablePublisher(NULL, &mSourceCatalog);
SuccessOrExit(err);
mTraitVersionSet[kTestADataSink0Index].versionInfo = mTestADataSink0.GetVersion();
mTraitVersionSet[kTestADataSink0Index].next = NULL;
mTraitVersionSet[kTestADataSink1Index].versionInfo = mTestADataSink1.GetVersion();
mTraitVersionSet[kTestADataSink1Index].next = NULL;
mTraitVersionSet[kTestBDataSinkIndex].versionInfo = mTestBDataSink.GetVersion();
mTraitVersionSet[kTestBDataSinkIndex].next = NULL;
mTraitVersionSet[kLocaleCapabilitiesTraitSinkIndex].versionInfo = mLocaleCapabilitiesDataSink.GetVersion();
mTraitVersionSet[kLocaleCapabilitiesTraitSinkIndex].next = NULL;
mSinkAddressList[kTestADataSink0Index] = &mTestADataSink0;
mSinkAddressList[kTestADataSink1Index] = &mTestADataSink1;
mSinkAddressList[kTestBDataSinkIndex] = &mTestBDataSink;
mSinkAddressList[kLocaleCapabilitiesTraitSinkIndex] = &mLocaleCapabilitiesDataSink;
Command_End();
exit:
return err;
}
void MockWdmSubscriptionResponderImpl::DumpPublisherTraitChecksum(int inTraitDataSourceIndex)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
TraitDataSource *dataSource;
err = mSourceCatalog.Locate(mTraitHandleSet[inTraitDataSourceIndex], &dataSource);
SuccessOrExit(err);
::DumpPublisherTraitChecksum(dataSource);
exit:
WeaveLogFunctError(err);
}
void MockWdmSubscriptionResponderImpl::DumpClientTraitChecksum(int inTraitDataSinkIndex)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
TraitDataSink *dataSink;
TraitSchemaEngine::IDataSourceDelegate *dataSource;
dataSource = mSinkAddressList[inTraitDataSinkIndex];
err = mSinkCatalog.Locate(mTraitHandleSet[inTraitDataSinkIndex], &dataSink);
SuccessOrExit(err);
::DumpClientTraitChecksum(dataSink->GetSchemaEngine(), dataSource);
exit:
WeaveLogFunctError(err);
}
void MockWdmSubscriptionResponderImpl::DumpClientTraits(void)
{
switch (mTestCaseId)
{
case kTestCase_IntegrationTrait:
DumpClientTraitChecksum(kLocaleCapabilitiesTraitSinkIndex);
break;
case kTestCase_TestTrait:
case kTestCase_CompatibleVersionedRequest:
case kTestCase_ForwardCompatibleVersionedRequest:
case kTestCase_IncompatibleVersionedCommandRequest:
DumpClientTraitChecksum(kTestADataSink0Index);
DumpClientTraitChecksum(kTestADataSink1Index);
DumpClientTraitChecksum(kTestBDataSinkIndex);
break;
case kTestCase_TestOversizeTrait1:
case kTestCase_TestOversizeTrait2:
DumpClientTraitChecksum(kTestADataSink0Index);
DumpClientTraitChecksum(kTestADataSink1Index);
break;
}
}
void MockWdmSubscriptionResponderImpl::DumpPublisherTraits(void)
{
switch (mTestCaseId)
{
case kTestCase_IntegrationTrait:
DumpPublisherTraitChecksum(kLocaleSettingsTraitSourceIndex);
DumpPublisherTraitChecksum(kApplicationKeysTraitSourceIndex);
break;
case kTestCase_TestTrait:
case kTestCase_CompatibleVersionedRequest:
case kTestCase_ForwardCompatibleVersionedRequest:
case kTestCase_IncompatibleVersionedCommandRequest:
DumpPublisherTraitChecksum(kTestATraitSource0Index);
DumpPublisherTraitChecksum(kTestATraitSource1Index);
DumpPublisherTraitChecksum(kTestBTraitSourceIndex);
DumpPublisherTraitChecksum(kLocaleSettingsTraitSourceIndex);
break;
case kTestCase_TestOversizeTrait1:
DumpPublisherTraitChecksum(kTestATraitSource0Index);
DumpPublisherTraitChecksum(kTestATraitSource1Index);
DumpPublisherTraitChecksum(kLocaleSettingsTraitSourceIndex);
break;
case kTestCase_TestOversizeTrait2:
DumpPublisherTraitChecksum(kLocaleSettingsTraitSourceIndex);
DumpPublisherTraitChecksum(kTestATraitSource0Index);
DumpPublisherTraitChecksum(kTestATraitSource1Index);
break;
}
}
void MockWdmSubscriptionResponderImpl::EngineEventCallback (void * const aAppState,
SubscriptionEngine::EventID aEvent,
const SubscriptionEngine::InEventParam & aInParam, SubscriptionEngine::OutEventParam & aOutParam)
{
MockWdmSubscriptionResponderImpl * const responder = reinterpret_cast<MockWdmSubscriptionResponderImpl *>(aAppState);
switch (aEvent)
{
case SubscriptionEngine::kEvent_OnIncomingSubscribeRequest:
WeaveLogDetail(DataManagement, "Engine->kEvent_OnIncomingSubscribeRequest peer = 0x%" PRIX64, aInParam.mIncomingSubscribeRequest.mEC->PeerNodeId);
aOutParam.mIncomingSubscribeRequest.mHandlerAppState = responder;
aOutParam.mIncomingSubscribeRequest.mHandlerEventCallback = MockWdmSubscriptionResponderImpl::PublisherEventCallback;
aOutParam.mIncomingSubscribeRequest.mRejectRequest = false;
aInParam.mIncomingSubscribeRequest.mBinding->SetDefaultResponseTimeout(kResponseTimeoutMsec);
aInParam.mIncomingSubscribeRequest.mBinding->SetDefaultWRMPConfig(gWRMPConfig);
break;
default:
SubscriptionEngine::DefaultEventHandler(aEvent, aInParam, aOutParam);
break;
}
}
void MockWdmSubscriptionResponderImpl::AddNewVersion(int aTraitDataSinkIndex)
{
VersionNode * curr = &mTraitVersionSet[aTraitDataSinkIndex];
while (curr->next != NULL)
{
curr = curr->next;
}
if (curr->versionInfo != mSinkCatalogStore[aTraitDataSinkIndex].mItem->GetVersion())
{
VersionNode * updatingVersion = (VersionNode *)malloc(sizeof(VersionNode));
WeaveLogDetail(DataManagement, "Trait %u version is changed %" PRIu64 " ---> %" PRIu64, aTraitDataSinkIndex, curr->versionInfo, mSinkCatalogStore[aTraitDataSinkIndex].mItem->GetVersion());
updatingVersion->versionInfo = mSinkCatalogStore[aTraitDataSinkIndex].mItem->GetVersion();
updatingVersion->next = NULL;
curr->next = updatingVersion;
}
}
void MockWdmSubscriptionResponderImpl::PublisherEventCallback (void * const aAppState,
SubscriptionHandler::EventID aEvent, const SubscriptionHandler::InEventParam & aInParam, SubscriptionHandler::OutEventParam & aOutParam)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
MockWdmSubscriptionResponderImpl * const responder = reinterpret_cast<MockWdmSubscriptionResponderImpl *>(aAppState);
switch (aEvent)
{
case SubscriptionHandler::kEvent_OnSubscribeRequestParsed:
WeaveLogDetail(DataManagement, "Publisher->kEvent_OnSubscribeRequestParsed");
// ideally this number should be set to something for cloud service, and something else for everyone else
// we can potentially copy this from the client side, but it would take considerable amount of code to be generic enough
// setting to some constant here seems to be easier
aInParam.mSubscribeRequestParsed.mHandler->GetBinding()->SetDefaultResponseTimeout(kResponseTimeoutMsec);
aInParam.mSubscribeRequestParsed.mHandler->GetBinding()->SetDefaultWRMPConfig(gWRMPConfig);
switch (responder->mTestCaseId)
{
case kTestCase_RejectIncomingSubscribeRequest:
// reject right here and release the resources associated with this incoming request
aInParam.mSubscribeRequestParsed.mHandler->EndSubscription(nl::Weave::Profiles::kWeaveProfile_Common,
nl::Weave::Profiles::Common::kStatus_Canceled);
break;
default:
WeaveLogDetail(DataManagement, "Liveness check range provided by client %u - %u sec. Set to %u sec",
aInParam.mSubscribeRequestParsed.mTimeoutSecMin,
aInParam.mSubscribeRequestParsed.mTimeoutSecMax,
responder->mTimeBetweenLivenessCheckSec);
aInParam.mSubscribeRequestParsed.mHandler->AcceptSubscribeRequest(responder->mTimeBetweenLivenessCheckSec);
}
break;
case SubscriptionHandler::kEvent_OnExchangeStart:
WeaveLogDetail(DataManagement, "Publisher->kEvent_OnExchangeStart");
break;
case SubscriptionHandler::kEvent_OnSubscriptionEstablished:
if (true == gClearDataSink || true == gCleanStatus)
{
responder->DumpPublisherTraits();
gCleanStatus = false;
}
WeaveLogDetail(DataManagement, "Publisher->kEvent_OnSubscriptionEstablished");
gSubscriptionHandler = aInParam.mSubscriptionEstablished.mHandler;
gBinding = gSubscriptionHandler->GetBinding();
gBinding->AddRef();
if (responder->mIsMutualSubscription)
{
if (NULL != responder->mSubscriptionClient)
{
WeaveLogDetail(DataManagement, "Skip mutual subscription setup, for we only have one client");
}
else
{
WeaveLogDetail(DataManagement, "Creating mutual subscription");
switch (responder->mTestCaseId)
{
case kTestCase_TestTrait:
responder->mNumPaths = 3;
responder->mTraitPaths[0].mTraitDataHandle = responder->mTraitHandleSet[kTestADataSink0Index];
responder->mTraitPaths[0].mPropertyPathHandle = kRootPropertyPathHandle;
responder->mTraitPaths[1].mTraitDataHandle = responder->mTraitHandleSet[kTestADataSink1Index];
responder->mTraitPaths[1].mPropertyPathHandle = kRootPropertyPathHandle;
responder->mTraitPaths[2].mTraitDataHandle = responder->mTraitHandleSet[kTestBDataSinkIndex];
responder->mTraitPaths[2].mPropertyPathHandle = kRootPropertyPathHandle;
break;
case kTestCase_IntegrationTrait:
responder->mNumPaths = 1;
responder->mTraitPaths[0].mTraitDataHandle = responder->mTraitHandleSet[kLocaleCapabilitiesTraitSinkIndex];
responder->mTraitPaths[0].mPropertyPathHandle = kRootPropertyPathHandle;
break;
case kTestCase_TestOversizeTrait1:
case kTestCase_TestOversizeTrait2:
responder->mNumPaths = 3;
responder->mTraitPaths[0].mTraitDataHandle = responder->mTraitHandleSet[kTestADataSink0Index];
responder->mTraitPaths[0].mPropertyPathHandle = kRootPropertyPathHandle;
responder->mTraitPaths[1].mTraitDataHandle = responder->mTraitHandleSet[kTestADataSink1Index];
responder->mTraitPaths[1].mPropertyPathHandle = kRootPropertyPathHandle;
responder->mTraitPaths[2].mTraitDataHandle = responder->mTraitHandleSet[kTestBDataSinkIndex];
responder->mTraitPaths[2].mPropertyPathHandle = kRootPropertyPathHandle;
break;
case kTestCase_CompatibleVersionedRequest:
case kTestCase_ForwardCompatibleVersionedRequest:
case kTestCase_IncompatibleVersionedRequest:
case kTestCase_IncompatibleVersionedCommandRequest:
responder->mNumPaths = 3;
for (int i = 0; i < 3; i++) {
if (responder->mTestCaseId == kTestCase_CompatibleVersionedRequest) {
responder->mVersionedTraitPaths[i].mRequestedVersionRange.mMinVersion = 1;
responder->mVersionedTraitPaths[i].mRequestedVersionRange.mMaxVersion = 1;
}
else if (responder->mTestCaseId == kTestCase_ForwardCompatibleVersionedRequest) {
responder->mVersionedTraitPaths[i].mRequestedVersionRange.mMinVersion = 1;
responder->mVersionedTraitPaths[i].mRequestedVersionRange.mMaxVersion = 4;
}
else if (responder->mTestCaseId == kTestCase_IncompatibleVersionedRequest) {
responder->mVersionedTraitPaths[i].mRequestedVersionRange.mMinVersion = 2;
responder->mVersionedTraitPaths[i].mRequestedVersionRange.mMaxVersion = 4;
}
else if (responder->mTestCaseId == kTestCase_IncompatibleVersionedCommandRequest) {
responder->mVersionedTraitPaths[i].mRequestedVersionRange.mMinVersion = 1;
responder->mVersionedTraitPaths[i].mRequestedVersionRange.mMaxVersion = 4;
}
}
responder->mVersionedTraitPaths[0].mTraitDataHandle = responder->mTraitHandleSet[kTestADataSink0Index];
responder->mVersionedTraitPaths[0].mPropertyPathHandle = kRootPropertyPathHandle;
responder->mVersionedTraitPaths[1].mTraitDataHandle = responder->mTraitHandleSet[kTestADataSink1Index];
responder->mVersionedTraitPaths[1].mPropertyPathHandle = kRootPropertyPathHandle;
responder->mVersionedTraitPaths[2].mTraitDataHandle = responder->mTraitHandleSet[kTestBDataSinkIndex];
responder->mVersionedTraitPaths[2].mPropertyPathHandle = kRootPropertyPathHandle;
break;
}
err = SubscriptionEngine::GetInstance()->NewClient(&(responder->mSubscriptionClient),
aInParam.mSubscriptionEstablished.mHandler->GetBinding(),
responder, ClientEventCallback,
&(responder->mSinkCatalog), kResponseTimeoutMsec * 2);
VerifyOrExit(err == WEAVE_NO_ERROR, gBinding->Release());
// TODO: EVENT-DEMO
responder->mSubscriptionClient->InitiateCounterSubscription(
responder->mTimeBetweenLivenessCheckSec);
}
}
else
{
if (gNumDataChangeBeforeCancellation != 0)
{
// alter data every gTimeBetweenDataChangeMsec milliseconds
responder->mExchangeMgr->MessageLayer->SystemLayer->StartTimer(gTimeBetweenDataChangeMsec, HandleDataFlipTimeout, aAppState);
}
else
{
if (gFinalStatus != kIdle)
{
switch (gFinalStatus)
{
case kPublisherCancel:
case kPublisherAbort:
responder->mExchangeMgr->MessageLayer->SystemLayer->StartTimer(kMonitorCurrentStateInterval, MonitorPublisherCurrentState, responder);
break;
case kClientCancel:
case kClientAbort:
responder->mExchangeMgr->MessageLayer->SystemLayer->StartTimer(kMonitorCurrentStateInterval, MonitorClientCurrentState, responder);
break;
default:
break;
}
}
}
}
break;
case SubscriptionHandler::kEvent_OnSubscriptionTerminated:
WeaveLogDetail(DataManagement, "Publisher->kEvent_OnSubscriptionTerminated. Reason: %u, peer = 0x%" PRIX64 "\n",
aInParam.mSubscriptionTerminated.mReason,
aInParam.mSubscriptionTerminated.mHandler->GetPeerNodeId());
switch (gFinalStatus)
{
case kPublisherCancel:
case kPublisherAbort:
responder->mExchangeMgr->MessageLayer->SystemLayer->CancelTimer(MonitorPublisherCurrentState, responder);
break;
case kClientCancel:
case kClientAbort:
responder->mExchangeMgr->MessageLayer->SystemLayer->CancelTimer(MonitorClientCurrentState, responder);
break;
case kIdle:
default:
break;
}
if (gNumDataChangeBeforeCancellation != 0)
{
//responder->mExchangeMgr->MessageLayer->SystemLayer->CancelTimer(HandleDataFlipTimeout, aAppState);
}
HandleClientRelease(responder);
HandlePublisherRelease();
gResponderState.init();
responder->onCompleteTest();
break;
default:
SubscriptionHandler::DefaultEventHandler(aEvent, aInParam, aOutParam);
break;
}
exit:
if (err != WEAVE_NO_ERROR && gSubscriptionHandler)
{
// tell the handler to cancel
(void)gSubscriptionHandler->EndSubscription();
}
WeaveLogFunctError(err);
}
void MockWdmSubscriptionResponderImpl::PrintVersionsLog()
{
for (int i = 0; i< kNumTraitHandles; i++)
{
VersionNode * pre = &mTraitVersionSet[i];
VersionNode * curr = mTraitVersionSet[i].next;
printf("Responder's trait %u versions log is : %" PRIu64, i, pre->versionInfo);
while (curr != NULL)
{
pre = curr;
curr = curr->next;
printf(" ==> %" PRIu64, pre->versionInfo);
}
printf("\n");
mTraitVersionSet[i].next = NULL;
}
}
void MockWdmSubscriptionResponderImpl::ClearDataSinkState(void)
{
gClearDataSink = true;
}
void MockWdmSubscriptionResponderImpl::ClearDataSinkIterator(void *aTraitInstance, TraitDataHandle aHandle, void *aContext)
{
MockTraitDataSink *traitInstance = static_cast<MockTraitDataSink *>(aTraitInstance);
traitInstance->ResetDataSink();
}
void MockWdmSubscriptionResponderImpl::ClientEventCallback (void * const aAppState, SubscriptionClient::EventID aEvent,
const SubscriptionClient::InEventParam & aInParam, SubscriptionClient::OutEventParam & aOutParam)
{
MockWdmSubscriptionResponderImpl * const responder = reinterpret_cast<MockWdmSubscriptionResponderImpl *>(aAppState);
switch (aEvent)
{
case SubscriptionClient::kEvent_OnExchangeStart:
WeaveLogDetail(DataManagement, "Client->kEvent_OnExchangeStart");
break;
case SubscriptionClient::kEvent_OnSubscribeRequestPrepareNeeded:
WeaveLogDetail(DataManagement, "Client->kEvent_OnSubscribeRequestPrepareNeeded");
if (gSubscriptionHandler->GetSubscriptionId(&(aOutParam.mSubscribeRequestPrepareNeeded.mSubscriptionId))
!= WEAVE_NO_ERROR)
{
WeaveLogDetail(DataManagement, "Client->kEvent_OnSubscribeRequestPrepareNeeded invalid state");
HandleClientRelease(aAppState);
}
else
{
if (responder->mTestCaseId >= kTestCase_CompatibleVersionedRequest && responder->mTestCaseId <= kTestCase_IncompatibleVersionedCommandRequest) {
aOutParam.mSubscribeRequestPrepareNeeded.mVersionedPathList = responder->mVersionedTraitPaths;
}
else {
aOutParam.mSubscribeRequestPrepareNeeded.mPathList = responder->mTraitPaths;
}
aOutParam.mSubscribeRequestPrepareNeeded.mPathListSize = responder->mNumPaths;
aOutParam.mSubscribeRequestPrepareNeeded.mNeedAllEvents = true;
aOutParam.mSubscribeRequestPrepareNeeded.mLastObservedEventList = NULL;
aOutParam.mSubscribeRequestPrepareNeeded.mLastObservedEventListSize = 0;
}
break;
case SubscriptionClient::kEvent_OnSubscriptionEstablished:
WeaveLogDetail(DataManagement, "Client->kEvent_OnSubscriptionEstablished");
WeaveLogDetail(DataManagement, "Liveness Timeout: %u msec", aInParam.mSubscriptionEstablished.mClient->GetLivenessTimeoutMsec());
if (gNumDataChangeBeforeCancellation != 0)
{
// alter data every gTimeBetweenDataChangeMsec milliseconds
responder->mExchangeMgr->MessageLayer->SystemLayer->StartTimer(gTimeBetweenDataChangeMsec, HandleDataFlipTimeout, aAppState);
}
else
{
if (gFinalStatus != kIdle)
{
switch (gFinalStatus)
{
case kPublisherCancel:
case kPublisherAbort:
responder->mExchangeMgr->MessageLayer->SystemLayer->StartTimer(kMonitorCurrentStateInterval, MonitorPublisherCurrentState, responder);
break;
case kClientCancel:
case kClientAbort:
responder->mExchangeMgr->MessageLayer->SystemLayer->StartTimer(kMonitorCurrentStateInterval, MonitorClientCurrentState, responder);
break;
default:
break;
}
}
}
break;
case SubscriptionClient::kEvent_OnNotificationRequest:
WeaveLogDetail(DataManagement, "Client->kEvent_OnNotificationRequest");
break;
case SubscriptionClient::kEvent_OnNotificationProcessed:
WeaveLogDetail(DataManagement, "Client->kEvent_OnNotificationProcessed");
switch (responder->mTestCaseId)
{
case kTestCase_IntegrationTrait:
responder->AddNewVersion(responder->kLocaleCapabilitiesTraitSinkIndex);
break;
case kTestCase_TestTrait:
case kTestCase_CompatibleVersionedRequest:
case kTestCase_ForwardCompatibleVersionedRequest:
case kTestCase_IncompatibleVersionedCommandRequest:
responder->AddNewVersion(responder->kTestADataSink0Index);
responder->AddNewVersion(responder->kTestADataSink1Index);
responder->AddNewVersion(responder->kTestBDataSinkIndex);
break;
case kTestCase_TestOversizeTrait1:
case kTestCase_TestOversizeTrait2:
responder->AddNewVersion(responder->kTestADataSink0Index);
responder->AddNewVersion(responder->kTestADataSink1Index);
break;
}
responder->DumpClientTraits();
break;
case SubscriptionClient::kEvent_OnSubscriptionTerminated:
WeaveLogDetail(DataManagement, "Client->kEvent_OnSubscriptionTerminated, Reason: %u, peer = 0x%" PRIX64 "\n",
aInParam.mSubscriptionTerminated.mReason,
aInParam.mSubscriptionTerminated.mClient->GetPeerNodeId());
switch (gFinalStatus)
{
case kPublisherCancel:
case kPublisherAbort:
responder->mExchangeMgr->MessageLayer->SystemLayer->CancelTimer(MonitorPublisherCurrentState, responder);
break;
case kClientCancel:
case kClientAbort:
responder->mExchangeMgr->MessageLayer->SystemLayer->CancelTimer(MonitorClientCurrentState, responder);
break;
case kIdle:
default:
break;
}
if (gNumDataChangeBeforeCancellation != 0)
{
responder->mExchangeMgr->MessageLayer->SystemLayer->CancelTimer(HandleDataFlipTimeout, responder);
}
if (gClearDataSink)
{
responder->mSinkCatalog.Iterate(MockWdmSubscriptionResponderImpl::ClearDataSinkIterator, NULL);
}
HandleClientRelease(responder);
HandlePublisherRelease();
gResponderState.init();
responder->onCompleteTest();
break;
default:
SubscriptionClient::DefaultEventHandler(aEvent, aInParam, aOutParam);
break;
}
}
void MockWdmSubscriptionResponderImpl::HandlePublisherComplete()
{
if (NULL != gSubscriptionHandler)
{
if (gFinalStatus == kPublisherCancel)
{
(void)gSubscriptionHandler->EndSubscription();
}
if (gFinalStatus == kPublisherAbort)
{
(void)gSubscriptionHandler->AbortSubscription();
}
}
}
void MockWdmSubscriptionResponderImpl::HandleClientRelease(void *aAppState)
{
MockWdmSubscriptionResponderImpl * const responder = reinterpret_cast<MockWdmSubscriptionResponderImpl *>(aAppState);
if (NULL != responder->mSubscriptionClient)
{
responder->mSubscriptionClient->Free();
responder->mSubscriptionClient = NULL;
}
}
void MockWdmSubscriptionResponderImpl::HandleClientComplete(void *aAppState)
{
MockWdmSubscriptionResponderImpl * const responder = reinterpret_cast<MockWdmSubscriptionResponderImpl *>(aAppState);
if (NULL != responder->mSubscriptionClient)
{
if (gFinalStatus == kClientCancel)
{
(void)responder->mSubscriptionClient->EndSubscription();
}
if (gFinalStatus == kClientAbort)
{
(void)responder->mSubscriptionClient->AbortSubscription();
}
}
}
void MockWdmSubscriptionResponderImpl::HandlePublisherRelease()
{
gSubscriptionHandler = NULL;
if (NULL != gBinding)
{
gBinding->Release();
gBinding = NULL;
}
}
void MockWdmSubscriptionResponderImpl::Command_End(const bool aAbort)
{
WeaveLogDetail(DataManagement, "Responder %s: state: %d", __func__, mCmdState);
(void)mExchangeMgr->MessageLayer->SystemLayer->CancelTimer(HandleCustomCommandTimeout, this);
mCmdState = kCmdState_Idle;
if (NULL != mEcCommand)
{
// this might be needed, for the test infrastructure re-init this object multiple times
// ExchangeContext::Close would gracefully close this exchange, while ExchangeContext::Abort
// would forcefully reclaim all resources
if (aAbort)
{
mEcCommand->Abort();
}
else
{
mEcCommand->Close();
}
mEcCommand = NULL;
}
}
void MockWdmSubscriptionResponderImpl::HandleCustomCommandTimeout(nl::Weave::System::Layer* aSystemLayer, void *aAppState, ::nl::Weave::System::Error aErr)
{
MockWdmSubscriptionResponderImpl * const pResponder = reinterpret_cast<MockWdmSubscriptionResponderImpl *>(aAppState);
WeaveLogDetail(DataManagement, "Responder %s", __func__);
pResponder->Command_End(true);
}
void MockWdmSubscriptionResponderImpl::OnMessageReceivedForCustomCommand (nl::Weave::ExchangeContext *aEC, const nl::Inet::IPPacketInfo *aPktInfo,
const nl::Weave::WeaveMessageInfo *aMsgInfo, uint32_t aProfileId,
uint8_t aMsgType, PacketBuffer *aPayload)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
MockWdmSubscriptionResponderImpl * pResponder = reinterpret_cast<MockWdmSubscriptionResponderImpl *>(aEC->AppState);
nl::Weave::Profiles::StatusReporting::StatusReport status;
enum
{
kMsgIdentified_Unknown = 0,
kMsgIdentified_StatusReport = 1,
kMsgIdentified_Response = 2,
kMsgIdentified_InProgress = 3,
} messageType = kMsgIdentified_Unknown;
WeaveLogDetail(DataManagement, "Responder %s: state: %d", __func__, pResponder->mCmdState);
VerifyOrExit(aEC == pResponder->mEcCommand, err = WEAVE_ERROR_INCORRECT_STATE);
VerifyOrExit(kCmdState_Idle != pResponder->mCmdState, err = WEAVE_ERROR_INCORRECT_STATE);
if ((nl::Weave::Profiles::kWeaveProfile_Common == aProfileId) && (nl::Weave::Profiles::Common::kMsgType_StatusReport == aMsgType))
{
// Note that payload is not freed in this call to parse
err = nl::Weave::Profiles::StatusReporting::StatusReport::parse(aPayload, status);
SuccessOrExit(err);
messageType = kMsgIdentified_StatusReport;
WeaveLogError(DataManagement, "Received Status Report 0x%" PRIX32 " : 0x%" PRIX16, status.mProfileId, status.mStatusCode);
}
else if ((nl::Weave::Profiles::kWeaveProfile_WDM == aProfileId) && (kMsgType_CustomCommandResponse == aMsgType))
{
// command response, implies the request succeeded to some degree
messageType = kMsgIdentified_Response;
}
else if ((nl::Weave::Profiles::kWeaveProfile_WDM == aProfileId) && (kMsgType_InProgress == aMsgType))
{
messageType = kMsgIdentified_InProgress;
}
else
{
messageType = kMsgIdentified_Unknown;
}
switch (pResponder->mCmdState)
{
case kCmdState_Requesting:
if (kMsgIdentified_InProgress == messageType)
{
// in progress, indicates the other side has received the request and is working on it
// note we could have different time out settings after receiving this in progress message.
// it's up to each individual trait.
WeaveLogDetail(DataManagement, "Received In Progress message. Waiting for a response");
// there is no payload in "in progress" message, so there is nothing to parse
pResponder->mCmdState = kCmdState_Operating;
// do not close this EC when we leave this function
aEC = NULL;
break;
}
// fall through intentional
case kCmdState_Operating:
if (kMsgIdentified_Response == messageType)
{
// command response, implies the request succeeded to some degree
WeaveLogDetail(DataManagement, "Response message, end");
nl::Weave::TLV::TLVReader reader;
reader.Init(aPayload);
err = reader.Next();
SuccessOrExit(err);
CustomCommandResponse::Parser response;
err = response.Init(reader);
SuccessOrExit(err);
#if WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
// this function only print out all recognized properties in the response
// check the parser class to see what else is available
err = response.CheckSchemaValidity();
SuccessOrExit(err);
#endif // WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
}
else
{
if (kMsgIdentified_StatusReport == messageType)
{
// status report, implies the request failed
WeaveLogDetail(DataManagement, "Status Report, end");
}
else
{
// unexpected message
WeaveLogDetail(DataManagement, "Unexpected message, end");
}
}
// reset state and close the exchange
pResponder->Command_End();
// aEC has been closed/aborted as part of Command_End
aEC = NULL;
break;
default:
// this is probably dead code
ExitNow(err = WEAVE_ERROR_INCORRECT_STATE);
}
exit:
WeaveLogFunctError(err);
if (WEAVE_NO_ERROR != err)
{
pResponder->Command_End(true);
// aEC has been closed/aborted as part of Command_End
aEC = NULL;
}
if (NULL != aEC)
{
aEC->Abort();
aEC = NULL;
}
if (NULL != aPayload)
{
PacketBuffer::Free(aPayload);
aPayload = NULL;
}
}
void MockWdmSubscriptionResponderImpl::Command_Send(void)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
PacketBuffer *msgBuf = PacketBuffer::New();
static uint32_t commandType = 1;
static uint32_t signatureType = 0; // static dummy signature. Values: 0 == None, 1 -- Weave Signature, 2 -- Group Key Signature
WeaveLogDetail(DataManagement, "Responder %s: state: %d", __func__, mCmdState);
printf("<<< TestCaseId %u >>>\n", mTestCaseId);
VerifyOrExit((NULL != gBinding) && (kCmdState_Idle == mCmdState) && (NULL == mEcCommand), err = WEAVE_ERROR_INCORRECT_STATE);
VerifyOrExit(NULL != msgBuf, err = WEAVE_ERROR_NO_MEMORY);
err = gBinding->NewExchangeContext(mEcCommand);
SuccessOrExit(err);
mEcCommand->AppState = this;
mEcCommand->OnMessageReceived = OnMessageReceivedForCustomCommand;
mEcCommand->OnResponseTimeout = NULL;
mEcCommand->OnSendError = NULL;
mEcCommand->OnAckRcvd = NULL;
{
nl::Weave::TLV::TLVWriter writer;
CustomCommandRequest::Builder request;
nl::Weave::Profiles::Time::timesync_t nowMicroSecs, deadline;
writer.Init(msgBuf);
err = request.Init(&writer);
SuccessOrExit(err);
Path::Builder & path = request.CreatePathBuilder();
if (mTestCaseId == kTestCase_ForwardCompatibleVersionedRequest) {
path.ProfileID(Schema::Nest::Test::Trait::TestATrait::kWeaveProfileId, SchemaVersionRange(4, 1)).InstanceID(1).EndOfPath();
}
else if (mTestCaseId == kTestCase_IncompatibleVersionedCommandRequest) {
path.ProfileID(Schema::Nest::Test::Trait::TestATrait::kWeaveProfileId, SchemaVersionRange(4, 2)).InstanceID(1).EndOfPath();
}
else {
path.ProfileID(Schema::Nest::Test::Trait::TestATrait::kWeaveProfileId).InstanceID(1).EndOfPath();
}
SuccessOrExit(path.GetError());
// Command Type: alternating
commandType = (1 == commandType) ? 2 : 1;
request.CommandType(commandType);
request.MustBeVersion(mTestADataSink1.GetVersion());
// It's safe to bail out after a series of operation, for
// SubscriptionRequest::Builder would internally turn to NOP after error is logged
SuccessOrExit(err = request.GetError());
nl::Weave::Platform::Time::GetSystemTime(&nowMicroSecs);
deadline = nowMicroSecs + kCommandTimeoutMicroSecs;
request.ExpiryTimeMicroSecond(deadline);
SuccessOrExit(err = request.GetError());
// Add arguments here
{
uint32_t dummyUInt = 7;
bool dummyBool = false;
nl::Weave::TLV::TLVType dummyType = nl::Weave::TLV::kTLVType_NotSpecified;
err = writer.StartContainer(nl::Weave::TLV::ContextTag(CustomCommandRequest::kCsTag_Argument), nl::Weave::TLV::kTLVType_Structure, dummyType);
SuccessOrExit(err);
err = writer.Put(nl::Weave::TLV::ContextTag(1), dummyUInt);
SuccessOrExit(err);
err = writer.PutBoolean(nl::Weave::TLV::ContextTag(2), dummyBool);
SuccessOrExit(err);
err = writer.EndContainer(dummyType);
SuccessOrExit(err);
}
switch (signatureType)
{
case 0: // dummy signature -- No signature
WeaveLogDetail(DataManagement, "Command with no authenticator" );
break;
case 1: // dummy signature -- Weave signature
{
nl::Weave::TLV::TLVType dummyType = nl::Weave::TLV::kTLVType_NotSpecified;
WeaveLogDetail(DataManagement, "Command with dummy WeaveSignature authenticator" );
err = writer.StartContainer(nl::Weave::TLV::ProfileTag(nl::Weave::Profiles::kWeaveProfile_Security, nl::Weave::Profiles::Security::kTag_WeaveSignature), nl::Weave::TLV::kTLVType_Structure, dummyType);
SuccessOrExit(err);
// dummy signature -- for now, just an algorithm specification
err = writer.Put(nl::Weave::TLV::ContextTag(nl::Weave::Profiles::Security::kTag_WeaveSignature_SignatureAlgorithm), nl::Weave::ASN1::kOID_SigAlgo_ECDSAWithSHA256);
SuccessOrExit(err);
err = writer.EndContainer(dummyType);
SuccessOrExit(err);
break;
}
case 2: // dummy signature -- Group key signature
{
nl::Weave::TLV::TLVType dummyType = nl::Weave::TLV::kTLVType_NotSpecified;
WeaveLogDetail(DataManagement, "Command with dummy Group Key Authenticator authenticator" );
err = writer.StartContainer(nl::Weave::TLV::ProfileTag(nl::Weave::Profiles::kWeaveProfile_Security, nl::Weave::Profiles::Security::kTag_GroupKeySignature), nl::Weave::TLV::kTLVType_Structure, dummyType);
SuccessOrExit(err);
// dummy signature -- for now, just an algorithm specification
err = writer.Put(nl::Weave::TLV::ContextTag(nl::Weave::Profiles::Security::kTag_GroupKeySignature_SignatureAlgorithm), nl::Weave::ASN1::kOID_SigAlgo_HMACWithSHA256);
SuccessOrExit(err);
err = writer.EndContainer(dummyType);
SuccessOrExit(err);
break;
}
}
request.EndOfRequest();
SuccessOrExit(err = request.GetError());
err = writer.Finalize();
SuccessOrExit(err);
if (commandType == 1)
{
signatureType = (signatureType + 1) % 3;
}
err = mEcCommand->SendMessage(nl::Weave::Profiles::kWeaveProfile_WDM, kMsgType_CustomCommandRequest,
msgBuf, nl::Weave::ExchangeContext::kSendFlag_ExpectResponse);
msgBuf = NULL;
SuccessOrExit(err);
}
err = mExchangeMgr->MessageLayer->SystemLayer->StartTimer(5000, HandleCustomCommandTimeout, this);
SuccessOrExit(err);
mCmdState = kCmdState_Requesting;
exit:
WeaveLogFunctError(err);
if (NULL != msgBuf)
{
PacketBuffer::Free(msgBuf);
msgBuf = NULL;
}
if (WEAVE_NO_ERROR != err)
{
Command_End(true);
}
}
void MockWdmSubscriptionResponderImpl::HandleDataFlipTimeout(nl::Weave::System::Layer* aSystemLayer, void *aAppState,
nl::Weave::System::Error aErr)
{
MockWdmSubscriptionResponderImpl * const responder = reinterpret_cast<MockWdmSubscriptionResponderImpl *>(aAppState);
IgnoreUnusedVariable(aErr);
if (gEnableDataFlip == true)
{
WeaveLogDetail(DataManagement, "\n\n\n\n\nFlipping data...");
switch (responder->mTestCaseId)
{
case kTestCase_IntegrationTrait:
case kTestCase_RejectIncomingSubscribeRequest:
responder->mLocaleSettingsDataSource.Mutate();
responder->mApplicationKeysTraitDataSource.Mutate();
SubscriptionEngine::GetInstance()->GetNotificationEngine()->Run();
break;
case kTestCase_TestTrait:
case kTestCase_CompatibleVersionedRequest:
case kTestCase_ForwardCompatibleVersionedRequest:
responder->mTestADataSource0.Mutate();
responder->mTestADataSource1.Mutate();
responder->mTestBDataSource.Mutate();
responder->mLocaleSettingsDataSource.Mutate();
responder->Command_Send();
SubscriptionEngine::GetInstance()->GetNotificationEngine()->Run();
break;
case kTestCase_IncompatibleVersionedCommandRequest:
responder->Command_Send();
SubscriptionEngine::GetInstance()->GetNotificationEngine()->Run();
break;
case kTestCase_TestOversizeTrait1:
responder->mTestADataSource0.Mutate();
responder->mTestADataSource1.Mutate();
responder->mLocaleSettingsDataSource.Mutate();
SubscriptionEngine::GetInstance()->GetNotificationEngine()->Run();
break;
case kTestCase_TestOversizeTrait2:
responder->mTestADataSource0.Mutate();
responder->mTestADataSource1.Mutate();
responder->mLocaleSettingsDataSource.Mutate();
SubscriptionEngine::GetInstance()->GetNotificationEngine()->Run();
break;
}
responder->DumpPublisherTraits();
}
if (gNumDataChangeBeforeCancellation == -1)
{
WeaveLogDetail(DataManagement, "immortal, no cancel or abort, completed cycle %d", gResponderState.mDataflipCount);
// alter data every gTimeBetweenDataChangeMsec milliseconds
aSystemLayer->StartTimer(gTimeBetweenDataChangeMsec, HandleDataFlipTimeout, responder);
++gResponderState.mDataflipCount;
}
else
{
WeaveLogDetail(DataManagement, "Completed cycle %d per %d", gResponderState.mDataflipCount, gNumDataChangeBeforeCancellation);
if (gResponderState.mDataflipCount == gNumDataChangeBeforeCancellation)
{
gResponderState.mDataflipCount = 1;
if (gFinalStatus != kIdle)
{
switch (gFinalStatus)
{
case kPublisherCancel:
case kPublisherAbort:
aSystemLayer->StartTimer(kMonitorCurrentStateInterval, MonitorPublisherCurrentState, responder);
break;
case kClientCancel:
case kClientAbort:
aSystemLayer->StartTimer(kMonitorCurrentStateInterval, MonitorClientCurrentState, responder);
break;
default:
break;
}
}
}
else
{
// alter data every gTimeBetweenDataChangeMsec milliseconds
++gResponderState.mDataflipCount;
aSystemLayer->StartTimer(gTimeBetweenDataChangeMsec, HandleDataFlipTimeout, responder);
}
}
}
void MockWdmSubscriptionResponderImpl::MonitorPublisherCurrentState (nl::Weave::System::Layer* aSystemLayer, void *aAppState, INET_ERROR aErr)
{
MockWdmSubscriptionResponderImpl * const responder = reinterpret_cast<MockWdmSubscriptionResponderImpl *>(aAppState);
if (NULL != gSubscriptionHandler)
{
if (gSubscriptionHandler->IsEstablishedIdle() && (NULL == responder->mSubscriptionClient || responder->mSubscriptionClient->IsEstablishedIdle()))
{
WeaveLogDetail(DataManagement, "state transitions to idle within %d msec", kMonitorCurrentStateInterval * kMonitorCurrentStateCnt);
gResponderState.mPublisherStateCount = 1;
HandlePublisherComplete();
if (!responder->mIsMutualSubscription)
{
HandlePublisherRelease();
WeaveLogDetail(DataManagement, "One_way: Good Iteration");
responder->onCompleteTest();
}
}
else
{
if (gResponderState.mPublisherStateCount < kMonitorCurrentStateCnt)
{
gResponderState.mPublisherStateCount ++;
aSystemLayer->StartTimer(kMonitorCurrentStateInterval, MonitorPublisherCurrentState, responder);
}
else
{
gResponderState.mPublisherStateCount = 1;
WeaveLogDetail(DataManagement, "state is not idle or aborted within %d msec", kMonitorCurrentStateInterval * kMonitorCurrentStateCnt);
(void)gSubscriptionHandler->AbortSubscription();
HandleClientRelease(responder);
HandlePublisherRelease();
responder->onCompleteTest();
}
}
}
else
{
WeaveLogDetail(DataManagement, "gSubscriptionHandler is NULL, and current session is torn down");
HandleClientRelease(responder);
HandlePublisherRelease();
responder->onCompleteTest();
}
}
void MockWdmSubscriptionResponderImpl::MonitorClientCurrentState (nl::Weave::System::Layer* aSystemLayer, void *aAppState, INET_ERROR aErr)
{
MockWdmSubscriptionResponderImpl * const responder = reinterpret_cast<MockWdmSubscriptionResponderImpl *>(aAppState);
if (NULL != responder->mSubscriptionClient)
{
if (responder->mSubscriptionClient->IsEstablishedIdle() && (NULL == gSubscriptionHandler || gSubscriptionHandler->IsEstablishedIdle()))
{
WeaveLogDetail(DataManagement, "state transitions to idle within %d msec", kMonitorCurrentStateInterval * kMonitorCurrentStateCnt);
gResponderState.mClientStateCount = 1;
HandleClientComplete(responder);
}
else
{
if (gResponderState.mClientStateCount < kMonitorCurrentStateCnt)
{
gResponderState.mClientStateCount ++;
aSystemLayer->StartTimer(kMonitorCurrentStateInterval, MonitorClientCurrentState, responder);
}
else
{
gResponderState.mClientStateCount = 1;
WeaveLogDetail(DataManagement, "state is not idle or aborted within %d msec", kMonitorCurrentStateInterval * kMonitorCurrentStateCnt);
(void)gSubscriptionHandler->AbortSubscription();
}
}
}
else
{
WeaveLogDetail(DataManagement, "mSubscriptionClient is NULL, and current session is torn down");
(void)gSubscriptionHandler->AbortSubscription();
HandleClientRelease(responder);
HandlePublisherRelease();
responder->onCompleteTest();
}
}
#endif // WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING