From 4f15e8047d14a21f4668b1922bc5c139afbb6a95 Mon Sep 17 00:00:00 2001 From: jadamcrain Date: Thu, 14 Jul 2011 10:57:51 -0400 Subject: [PATCH 1/9] Reworked the throughput test to check values as they are received in lock step --- APL/APL.vcproj | 4 + APL/AsyncTaskGroup.cpp | 38 +++-- APL/AsyncTaskGroup.h | 3 + APL/DataTypes.h | 2 +- APL/FlexibleDataObserver.h | 14 +- APL/GetKeys.h | 41 +++++ APL/PhysicalLayerMonitor.cpp | 36 ++-- APL/PhysicalLayerMonitor.h | 5 +- APL/PhysicalLayerMonitorStates.cpp | 29 ++-- APL/PhysicalLayerMonitorStates.h | 17 +- APL/Random.h | 9 + APLTestTools/APLTestTools.vcproj | 4 + APLTestTools/FanoutDataObserver.h | 72 ++++++++ DNP3/AsyncStackManager.cpp | 156 +++++++----------- DNP3/AsyncStackManager.h | 42 +++-- DNP3/DNP3.vcproj | 4 +- DNP3/LinkChannel.cpp | 6 + DNP3/LinkChannel.h | 3 +- DNP3/LinkLayerRouter.cpp | 14 +- DNP3/LinkRoute.cpp | 9 + DNP3/LinkRoute.h | 2 + DNP3Test/ComparingDataObserver.cpp | 119 +++++++++++++ DNP3Test/ComparingDataObserver.h | 113 +++++++++++++ DNP3Test/DNP3Test.vcproj | 8 + DNP3Test/IntegrationTest.cpp | 110 ++++++++---- DNP3Test/IntegrationTest.h | 106 ++++-------- DNP3Test/TestIntegration.cpp | 42 ++--- .../FlexibleObserverTerminalExtension.cpp | 4 +- 28 files changed, 702 insertions(+), 310 deletions(-) create mode 100755 APL/GetKeys.h create mode 100755 APLTestTools/FanoutDataObserver.h create mode 100755 DNP3Test/ComparingDataObserver.cpp create mode 100755 DNP3Test/ComparingDataObserver.h diff --git a/APL/APL.vcproj b/APL/APL.vcproj index 53dc80b6..57b3647f 100755 --- a/APL/APL.vcproj +++ b/APL/APL.vcproj @@ -548,6 +548,10 @@ RelativePath=".\Exception.h" > + + diff --git a/APL/AsyncTaskGroup.cpp b/APL/AsyncTaskGroup.cpp index 7d593f15..ddf6ef64 100644 --- a/APL/AsyncTaskGroup.cpp +++ b/APL/AsyncTaskGroup.cpp @@ -37,6 +37,7 @@ namespace apl AsyncTaskGroup::AsyncTaskGroup(ITimerSource* apTimerSrc, ITimeSource* apTimeSrc) : mIsRunning(false), + mShutdown(false), mpTimerSrc(apTimerSrc), mpTimeSrc(apTimeSrc), mpTimer(NULL) @@ -46,10 +47,7 @@ AsyncTaskGroup::AsyncTaskGroup(ITimerSource* apTimerSrc, ITimeSource* apTimeSrc) AsyncTaskGroup::~AsyncTaskGroup() { - if(mpTimer) { - mpTimer->Cancel(); - mpTimer = NULL; - } + this->Shutdown(); BOOST_FOREACH(AsyncTaskBase* p, mTaskVec) { delete p; @@ -94,6 +92,16 @@ void AsyncTaskGroup::Remove(AsyncTaskBase* apTask) throw ArgumentException(LOCATION, "Task not found"); } +void AsyncTaskGroup::Shutdown() +{ + if(mpTimer) { + mpTimer->Cancel(); + mpTimer = NULL; + } + + mShutdown = true; +} + void AsyncTaskGroup::Enable() { BOOST_FOREACH(AsyncTaskBase* p, mTaskVec) { @@ -142,18 +150,20 @@ AsyncTaskBase* AsyncTaskGroup::GetNext(const boost::posix_time::ptime& arTime) void AsyncTaskGroup::CheckState() { - ptime now = GetUTC(); - AsyncTaskBase* pTask = GetNext(now); + if(!mShutdown) { + ptime now = GetUTC(); + AsyncTaskBase* pTask = GetNext(now); - if(pTask == NULL) return; - if(pTask->NextRunTime() == max_date_time) return; + if(pTask == NULL) return; + if(pTask->NextRunTime() == max_date_time) return; - if(pTask->NextRunTime() <= now) { - mIsRunning = true; - pTask->Dispatch(); - } - else { - this->RestartTimer(pTask->NextRunTime()); + if(pTask->NextRunTime() <= now) { + mIsRunning = true; + pTask->Dispatch(); + } + else { + this->RestartTimer(pTask->NextRunTime()); + } } } diff --git a/APL/AsyncTaskGroup.h b/APL/AsyncTaskGroup.h index 62f95548..9da44dc1 100644 --- a/APL/AsyncTaskGroup.h +++ b/APL/AsyncTaskGroup.h @@ -57,6 +57,8 @@ class AsyncTaskGroup : private Uncopyable AsyncTaskContinuous* AddContinuous(int aPriority, const TaskHandler& arCallback, const std::string& arName = ""); void Remove(AsyncTaskBase* apTask); + void Shutdown(); + void Enable(); void Disable(); @@ -82,6 +84,7 @@ class AsyncTaskGroup : private Uncopyable AsyncTaskBase* GetNext(const boost::posix_time::ptime& arTime); bool mIsRunning; + bool mShutdown; ITimerSource* mpTimerSrc; ITimeSource* mpTimeSrc; ITimer* mpTimer; diff --git a/APL/DataTypes.h b/APL/DataTypes.h index 2cb3914c..6b340e24 100644 --- a/APL/DataTypes.h +++ b/APL/DataTypes.h @@ -33,8 +33,8 @@ class Binary : public BoolDataPoint { public: Binary(bool aValue, boost::uint8_t aQuality = BQ_RESTART) : BoolDataPoint(BQ_RESTART, DT_BINARY, BQ_STATE) { - SetValue(aValue); SetQuality(aQuality); + SetValue(aValue); } Binary() : BoolDataPoint(BQ_RESTART, DT_BINARY, BQ_STATE) {} diff --git a/APL/FlexibleDataObserver.h b/APL/FlexibleDataObserver.h index ca0af411..25151177 100644 --- a/APL/FlexibleDataObserver.h +++ b/APL/FlexibleDataObserver.h @@ -19,7 +19,6 @@ #ifndef __FLEXIBLE_DATA_OBSERVER_H_ #define __FLEXIBLE_DATA_OBSERVER_H_ - #include "DataInterfaces.h" #include "Lock.h" #include "SubjectBase.h" @@ -30,6 +29,12 @@ namespace apl { + +template +struct PointMap { + typedef std::map Type; +}; + /** Simple data obsever that stores the current value of anything it receives. SubjectBase implictly notifies observers of any updates. @@ -41,11 +46,6 @@ class FlexibleDataObserver : public apl::IDataObserver, public SubjectBase - struct PointMap { - typedef std::map Type; - }; - // allow direct access to the maps PointMap::Type mBinaryMap; PointMap::Type mAnalogMap; @@ -256,7 +256,7 @@ template void FlexibleDataObserver::Print(typename PointMap::Type& arMap) { int j = 0; - typename FlexibleDataObserver::PointMap::Type::iterator i = arMap.begin(); + typename PointMap::Type::iterator i = arMap.begin(); for(; i != arMap.end(); ++i) { std::cout << j << ", " << i->second.GetValue() << ", " << static_cast(i->second.GetQuality()) << std::endl; ++j; diff --git a/APL/GetKeys.h b/APL/GetKeys.h new file mode 100755 index 00000000..ffb730d8 --- /dev/null +++ b/APL/GetKeys.h @@ -0,0 +1,41 @@ +// +// Licensed to Green Energy Corp (www.greenenergycorp.com) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. Green Enery Corp licenses this file +// to you 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. +// + +#ifndef __KEY_KEYS_H_ +#define __KEY_KEYS_H_ + +#include + +namespace apl +{ + +template +static std::vector GetKeys(const T& arMap) +{ + std::vector ret; + for(typename T::const_iterator i = arMap.begin(); i != arMap.end(); ++i) { + ret.push_back(i->first); + } + return ret; +} + +} + +#endif + diff --git a/APL/PhysicalLayerMonitor.cpp b/APL/PhysicalLayerMonitor.cpp index 3f8de5ea..96a487f2 100755 --- a/APL/PhysicalLayerMonitor.cpp +++ b/APL/PhysicalLayerMonitor.cpp @@ -35,7 +35,8 @@ PhysicalLayerMonitor::PhysicalLayerMonitor(Logger* apLogger, IPhysicalLayerAsync mpPhys(apPhys), mpTimerSrc(apTimerSrc), mpOpenTimer(NULL), - mpState(MonitorStateSuspended::Inst()), + mpState(MonitorStateInit::Inst()), + mFinalShutdown(false), M_OPEN_RETRY(aOpenRetry) { assert(apPhys != NULL); @@ -62,22 +63,33 @@ void PhysicalLayerMonitor::AddObserver(IPhysicalLayerObserver* apObserver) void PhysicalLayerMonitor::WaitForShutdown() { - CriticalSection cs(&mLock); - while(this->GetState() != PLS_SHUTDOWN) cs.Wait(); + CriticalSection cs(&mLock); + while(!mFinalShutdown) cs.Wait(); } void PhysicalLayerMonitor::ChangeState(IMonitorState* apState) { - CriticalSection cs(&mLock); - LOG_BLOCK(LEV_INFO, mpState->ConvertToString() << " -> " << apState->ConvertToString() << " : " << mpPhys->ConvertStateToString()); + LOG_BLOCK(LEV_DEBUG, mpState->ConvertToString() << " -> " << apState->ConvertToString() << " : " << mpPhys->ConvertStateToString()); IMonitorState* pLast = mpState; + + CriticalSection cs(&mLock); mpState = apState; if(pLast->GetState() != apState->GetState()) { for(ObserverSet::iterator i = mObservers.begin(); i != mObservers.end(); ++i) (*i)->OnStateChange(apState->GetState()); - cs.Broadcast(); // signal to anyone waiting for a state change + + // signaling this way makes sure we're free and clear of the event that causes this + // before someone else and deletes + if(mpState->GetState() == PLS_SHUTDOWN) mpTimerSrc->Post(boost::bind(&PhysicalLayerMonitor::DoFinalShutdown, this)); } } +void PhysicalLayerMonitor::DoFinalShutdown() +{ + CriticalSection cs(&mLock); + mFinalShutdown = true; + cs.Broadcast(); +} + /* ------- User facing events that occurs ------- */ void PhysicalLayerMonitor::Start() @@ -122,11 +134,9 @@ void PhysicalLayerMonitor::OnOpenTimerExpiration() void PhysicalLayerMonitor::_OnOpenFailure() { - LOG_BLOCK(LEV_DEBUG, "_OnOpenFailure()"); - //This guard keeps the monitor from making callbacks after it is potentially deleted - bool shutdown = mpState->IsShuttingDown(); + LOG_BLOCK(LEV_DEBUG, "_OnOpenFailure()"); mpState->OnOpenFailure(this); - if(!shutdown) this->OnPhysicalLayerOpenFailureCallback(); + this->OnPhysicalLayerOpenFailureCallback(); } void PhysicalLayerMonitor::_OnLowerLayerUp() @@ -138,11 +148,9 @@ void PhysicalLayerMonitor::_OnLowerLayerUp() void PhysicalLayerMonitor::_OnLowerLayerDown() { - LOG_BLOCK(LEV_DEBUG, "_OnLowerLayerDown"); - //This guard keeps the monitor from making callbacks after it is potentially deleted - bool shutdown = mpState->IsShuttingDown(); + LOG_BLOCK(LEV_DEBUG, "_OnLowerLayerDown"); mpState->OnLayerClose(this); - if(!shutdown) this->OnPhysicalLayerCloseCallback(); + this->OnPhysicalLayerCloseCallback(); } /* ------- Actions for the states ------- */ diff --git a/APL/PhysicalLayerMonitor.h b/APL/PhysicalLayerMonitor.h index 72d45c66..2778ec97 100755 --- a/APL/PhysicalLayerMonitor.h +++ b/APL/PhysicalLayerMonitor.h @@ -89,6 +89,7 @@ class PhysicalLayerMonitor : public IHandlerAsync ITimerSource* mpTimerSrc; ITimer* mpOpenTimer; IMonitorState* mpState; + bool mFinalShutdown; /* --- Actions for the states to call --- */ @@ -99,10 +100,12 @@ class PhysicalLayerMonitor : public IHandlerAsync void OnOpenTimerExpiration(); /// Cancels the open timer - void CancelOpenTimer(); + void CancelOpenTimer(); /* --- Internal helper functions --- */ + void DoFinalShutdown(); + SigLock mLock; const millis_t M_OPEN_RETRY; diff --git a/APL/PhysicalLayerMonitorStates.cpp b/APL/PhysicalLayerMonitorStates.cpp index e9fa6b33..285b663b 100755 --- a/APL/PhysicalLayerMonitorStates.cpp +++ b/APL/PhysicalLayerMonitorStates.cpp @@ -110,8 +110,8 @@ void IgnoresSuspend::OnSuspendRequest(PhysicalLayerMonitor* apContext) void StartsOnClose::OnLayerClose(PhysicalLayerMonitor* apContext) { - MonitorStateActions::ChangeState(apContext, MonitorStateSuspended::Inst()); - apContext->Start(); + MonitorStateActions::ChangeState(apContext, MonitorStateOpening::Inst()); + MonitorStateActions::AsyncOpen(apContext); } /* --- IgnoresShutdown --- */ @@ -168,20 +168,25 @@ MonitorStateShutdown MonitorStateShutdown::mInstance; MonitorStateSuspended MonitorStateSuspended::mInstance; -void MonitorStateSuspended::OnStartRequest(PhysicalLayerMonitor* apContext) +/* --- Init --- */ + +MonitorStateInit MonitorStateInit::mInstance; + +/* ---- SuspendedBase --- */ +void MonitorStateSuspendedBase::OnStartRequest(PhysicalLayerMonitor* apContext) { MonitorStateActions::ChangeState(apContext, MonitorStateOpening::Inst()); MonitorStateActions::AsyncOpen(apContext); } -void MonitorStateSuspended::OnStartOneRequest(PhysicalLayerMonitor* apContext) +void MonitorStateSuspendedBase::OnStartOneRequest(PhysicalLayerMonitor* apContext) { MonitorStateActions::ChangeState(apContext, MonitorStateOpeningOne::Inst()); MonitorStateActions::AsyncOpen(apContext); } -void MonitorStateSuspended::OnShutdownRequest(PhysicalLayerMonitor* apContext) -{ +void MonitorStateSuspendedBase::OnShutdownRequest(PhysicalLayerMonitor* apContext) +{ MonitorStateActions::ChangeState(apContext, MonitorStateShutdown::Inst()); } @@ -292,19 +297,19 @@ void MonitorStateOpen::OnStartOneRequest(PhysicalLayerMonitor* apContext) void MonitorStateOpen::OnCloseRequest(PhysicalLayerMonitor* apContext) { - MonitorStateActions::ChangeState(apContext, MonitorStateClosing::Inst()); + MonitorStateActions::ChangeState(apContext, MonitorStateClosing::Inst()); MonitorStateActions::AsyncClose(apContext); } void MonitorStateOpen::OnSuspendRequest(PhysicalLayerMonitor* apContext) { - MonitorStateActions::ChangeState(apContext, MonitorStateSuspending::Inst()); + MonitorStateActions::ChangeState(apContext, MonitorStateSuspending::Inst()); MonitorStateActions::AsyncClose(apContext); } void MonitorStateOpen::OnShutdownRequest(PhysicalLayerMonitor* apContext) { - MonitorStateActions::ChangeState(apContext, MonitorStateShutingDown::Inst()); + MonitorStateActions::ChangeState(apContext, MonitorStateShutingDown::Inst()); MonitorStateActions::AsyncClose(apContext); } @@ -394,17 +399,17 @@ void MonitorStateClosing::OnSuspendRequest(PhysicalLayerMonitor* apContext) MonitorStateSuspending MonitorStateSuspending::mInstance; void MonitorStateSuspending::OnLayerClose(PhysicalLayerMonitor* apContext) -{ +{ MonitorStateActions::ChangeState(apContext, MonitorStateSuspended::Inst()); } void MonitorStateSuspending::OnStartRequest(PhysicalLayerMonitor* apContext) -{ +{ MonitorStateActions::ChangeState(apContext, MonitorStateClosing::Inst()); } void MonitorStateSuspending::OnShutdownRequest(PhysicalLayerMonitor* apContext) -{ +{ MonitorStateActions::ChangeState(apContext, MonitorStateShutingDown::Inst()); } diff --git a/APL/PhysicalLayerMonitorStates.h b/APL/PhysicalLayerMonitorStates.h index c86588ad..a0a8fae5 100755 --- a/APL/PhysicalLayerMonitorStates.h +++ b/APL/PhysicalLayerMonitorStates.h @@ -171,20 +171,29 @@ class MonitorStateShutdown : public virtual IMonitorState, MACRO_MONITOR_SINGLETON(MonitorStateShutdown, PLS_SHUTDOWN, true); }; -class MonitorStateSuspended : public virtual IMonitorState, +class MonitorStateSuspendedBase : public virtual IMonitorState, private NotOpening, private NotOpen, private NotWaitingForTimer, private IgnoresClose, private IgnoresSuspend -{ - MACRO_MONITOR_SINGLETON(MonitorStateSuspended, PLS_CLOSED, false); - +{ void OnStartRequest(PhysicalLayerMonitor* apContext); void OnStartOneRequest(PhysicalLayerMonitor* apContext); void OnShutdownRequest(PhysicalLayerMonitor* apContext); }; + +class MonitorStateSuspended : public MonitorStateSuspendedBase +{ + MACRO_MONITOR_SINGLETON(MonitorStateSuspended, PLS_CLOSED, false); +}; + +class MonitorStateInit : public MonitorStateSuspendedBase +{ + MACRO_MONITOR_SINGLETON(MonitorStateInit, PLS_CLOSED, false); +}; + class MonitorStateOpeningBase : public virtual IMonitorState, private NotOpen, private NotWaitingForTimer diff --git a/APL/Random.h b/APL/Random.h index df94ca6c..2c301e7f 100755 --- a/APL/Random.h +++ b/APL/Random.h @@ -58,6 +58,15 @@ class Random boost::variate_generator > nextRand; }; +class RandomBool : private Random +{ + public: + RandomBool() : Random(0,1) + {} + + bool NextBool() { return Next() ? true : false; } +}; + } diff --git a/APLTestTools/APLTestTools.vcproj b/APLTestTools/APLTestTools.vcproj index cc566a8e..45c1864d 100644 --- a/APLTestTools/APLTestTools.vcproj +++ b/APLTestTools/APLTestTools.vcproj @@ -276,6 +276,10 @@ + + diff --git a/APLTestTools/FanoutDataObserver.h b/APLTestTools/FanoutDataObserver.h new file mode 100755 index 00000000..51661636 --- /dev/null +++ b/APLTestTools/FanoutDataObserver.h @@ -0,0 +1,72 @@ +// +// Licensed to Green Energy Corp (www.greenenergycorp.com) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. Green Enery Corp licenses this file +// to you 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. +// +#ifndef __FANOUT_DATA_OBSERVER_H_ +#define __FANOUT_DATA_OBSERVER_H_ + +#include +#include + +namespace apl +{ + +template +class FanoutDataObserver : public IDataObserver +{ +public: + + void AddObserver(IDataObserver* apObserver) { + mObservers.push_back(apObserver); + } + + void _Start() { + mBuffer.Start(); + } + void _End() { + mBuffer.End(); + + BOOST_FOREACH(IDataObserver* p, mObservers) { + mBuffer.FlushUpdates(p, false); + } + } + + void _Update(const Binary& arPoint, size_t aIndex) { + mBuffer.Update(arPoint, aIndex); + } + void _Update(const Analog& arPoint, size_t aIndex) { + mBuffer.Update(arPoint, aIndex); + } + void _Update(const Counter& arPoint, size_t aIndex) { + mBuffer.Update(arPoint, aIndex); + } + void _Update(const ControlStatus& arPoint, size_t aIndex) { + mBuffer.Update(arPoint, aIndex); + } + void _Update(const SetpointStatus& arPoint, size_t aIndex) { + mBuffer.Update(arPoint, aIndex); + } + +private: + ChangeBuffer mBuffer; + std::vector mObservers; +}; + +} + +#endif + diff --git a/DNP3/AsyncStackManager.cpp b/DNP3/AsyncStackManager.cpp index 1db1d490..6162ca26 100644 --- a/DNP3/AsyncStackManager.cpp +++ b/DNP3/AsyncStackManager.cpp @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include #include @@ -46,16 +48,6 @@ namespace apl namespace dnp { -template -static std::vector GetKeys(T& arMap) -{ - std::vector ret; - for(typename T::iterator i = arMap.begin(); i != arMap.end(); ++i) { - ret.push_back(i->first); - } - return ret; -} - AsyncStackManager::AsyncStackManager(Logger* apLogger) : Loggable(apLogger), mService(), @@ -83,7 +75,7 @@ AsyncStackManager::~AsyncStackManager() std::vector AsyncStackManager::GetStackNames() { - return GetKeys(mStackNameToChannel); + return GetKeys(mStackMap); } std::vector AsyncStackManager::GetPortNames() @@ -117,10 +109,10 @@ ICommandAcceptor* AsyncStackManager::AddMaster( const std::string& arPortName, c Logger* pLogger = mpLogger->GetSubLogger(arStackName, aLevel); pLogger->SetVarName(arStackName); - boost::shared_ptr pMaster(new MasterStack(pLogger, &mTimerSrc, apPublisher, pChannel->GetGroup(), arCfg)); + MasterStack* pMaster = new MasterStack(pLogger, &mTimerSrc, apPublisher, pChannel->GetGroup(), arCfg); LinkRoute route(arCfg.link.RemoteAddr, arCfg.link.LocalAddr); - this->OnAddStack(arStackName, pMaster, pChannel, route); + this->AddStackToChannel(arStackName, pMaster, pChannel, route); // add any vto routers we've configured BOOST_FOREACH(VtoRouterConfig s, arCfg.vto.mRouterConfigs) { @@ -138,10 +130,10 @@ IDataObserver* AsyncStackManager::AddSlave( const std::string& arPortName, const Logger* pLogger = mpLogger->GetSubLogger(arStackName, aLevel); pLogger->SetVarName(arStackName); - boost::shared_ptr pSlave(new SlaveStack(pLogger, &mTimerSrc, apCmdAcceptor, arCfg)); + SlaveStack* pSlave = new SlaveStack(pLogger, &mTimerSrc, apCmdAcceptor, arCfg); LinkRoute route(arCfg.link.RemoteAddr, arCfg.link.LocalAddr); - this->OnAddStack(arStackName, pSlave, pChannel, route); + this->AddStackToChannel(arStackName, pSlave, pChannel, route); // add any vto routers we've configured BOOST_FOREACH(VtoRouterConfig s, arCfg.vto.mRouterConfigs) { @@ -155,33 +147,32 @@ void AsyncStackManager::AddVtoChannel(const std::string& arStackName, IVtoCallbacks* apCallbacks) { this->ThrowIfAlreadyShutdown(); - Stack* pStack = this->GetStackByName(arStackName); - pStack->GetVtoWriter()->AddVtoCallback(apCallbacks); - pStack->GetVtoReader()->AddVtoChannel(apCallbacks); + StackRecord rec = this->GetStackRecordByName(arStackName); + rec.stack->GetVtoWriter()->AddVtoCallback(apCallbacks); + rec.stack->GetVtoReader()->AddVtoChannel(apCallbacks); } void AsyncStackManager::RemoveVtoChannel(const std::string& arStackName, IVtoCallbacks* apCallbacks) { this->ThrowIfAlreadyShutdown(); - Stack* pStack = this->GetStackByName(arStackName); - pStack->GetVtoWriter()->RemoveVtoCallback(apCallbacks); - pStack->GetVtoReader()->RemoveVtoChannel(apCallbacks); + StackRecord rec = this->GetStackRecordByName(arStackName); + rec.stack->GetVtoWriter()->RemoveVtoCallback(apCallbacks); + rec.stack->GetVtoReader()->RemoveVtoChannel(apCallbacks); } void AsyncStackManager::StartVtoRouter(const std::string& arPortName, const std::string& arStackName, const VtoRouterSettings& arSettings) { this->ThrowIfAlreadyShutdown(); - Stack* pStack = this->GetStackByName(arStackName); - VtoRouter* pRouter = mVtoManager.StartRouter(arPortName, arSettings, pStack->GetVtoWriter()); + StackRecord rec = this->GetStackRecordByName(arStackName); + VtoRouter* pRouter = mVtoManager.StartRouter(arPortName, arSettings, rec.stack->GetVtoWriter()); this->AddVtoChannel(arStackName, pRouter); } void AsyncStackManager::StopVtoRouter(const std::string& arStackName, boost::uint8_t aVtoChannelId) { - this->ThrowIfAlreadyShutdown(); - Stack* pStack = this->GetStackByName(arStackName); - IVtoWriter* pWriter = pStack->GetVtoWriter(); + this->ThrowIfAlreadyShutdown(); + IVtoWriter* pWriter = this->GetVtoWriter(arStackName); VtoRouterManager::RouterRecord rec = mVtoManager.GetRouterOnWriter(pWriter, aVtoChannelId); this->RemoveVtoChannel(arStackName, rec.mpRouter.get()); mVtoManager.StopRouter(pWriter, aVtoChannelId); @@ -198,92 +189,48 @@ void AsyncStackManager::StopAllRoutersOnStack(const std::string& arStackName) IVtoWriter* AsyncStackManager::GetVtoWriter(const std::string& arStackName) { this->ThrowIfAlreadyShutdown(); - return this->GetStackByName(arStackName)->GetVtoWriter(); + return this->GetStackRecordByName(arStackName).stack->GetVtoWriter(); } // Remove a port and all associated stacks void AsyncStackManager::RemovePort(const std::string& arPortName) { this->ThrowIfAlreadyShutdown(); - LinkChannel* pChannel = this->GetChannelOrExcept(arPortName); - - vector stacks = this->StacksOnChannel(arPortName); - BOOST_FOREACH(string s, stacks) { - this->SeverStack(pChannel, s); - } + std::auto_ptr pChannel(this->GetChannelOrExcept(arPortName)); //will delete at end of function + mChannelNameToChannel.erase(arPortName); { // Tell the channel to shut down permanently Transaction tr(&mSuspendTimerSource); - pChannel->BeginShutdown(); + pChannel->GetGroup()->Shutdown(); // no more task callbacks + pChannel->BeginShutdown(); } - - pChannel->WaitUntilShutdown(); + pChannel->WaitUntilShutdown(); + + vector stacks = pChannel->StacksOnChannel(); + BOOST_FOREACH(string s, stacks) { + delete this->SeverStackFromChannel(s); + } + this->mScheduler.ReleaseGroup(pChannel->GetGroup()); - mChannelNameToChannel.erase(arPortName); // remove the physical layer from the list mMgr.Remove(arPortName); } -std::vector AsyncStackManager::StacksOnChannel(const std::string& arPortName) -{ - this->ThrowIfAlreadyShutdown(); - std::vector ret; - for(StackToChannelMap::iterator i = this->mStackNameToChannel.begin(); i != mStackNameToChannel.end(); ++i) { - if(i->second->Name() == arPortName) { - ret.push_back(i->first); - } - } - return ret; -} - void AsyncStackManager::RemoveStack(const std::string& arStackName) { - this->ThrowIfAlreadyShutdown(); - LinkChannel* pChannel = this->GetChannelByStackName(arStackName); - this->SeverStack(pChannel, arStackName); + this->ThrowIfAlreadyShutdown(); + delete this->SeverStackFromChannel(arStackName); } -void AsyncStackManager::SeverStack(LinkChannel* apChannel, const std::string& arStackName) +AsyncStackManager::StackRecord AsyncStackManager::GetStackRecordByName(const std::string& arStackName) { - LOG_BLOCK(LEV_INFO, "Begin severing stack: " << arStackName); - // Decouple and stop the stack first, this doesn't delete it yet - { - Transaction tr(&mSuspendTimerSource); //need to pause execution so that this action is safe - apChannel->RemoveStackFromChannel(arStackName); - } - LOG_BLOCK(LEV_INFO, "Done severing stack: " << arStackName); - - // Now stop any associated vto routers - IVtoWriter* pWriter = this->GetStackByName(arStackName)->GetVtoWriter(); - std::vector records = mVtoManager.GetAllRoutersOnWriter(pWriter); - BOOST_FOREACH(VtoRouterManager::RouterRecord rec, records) { - this->RemoveVtoChannel(arStackName, rec.mpRouter.get()); - mVtoManager.StopRouter(pWriter, rec.mVtoChannelId); //router gets deleted here - } - - mStackNameToChannel.erase(arStackName); - mStackNameToStack.erase(arStackName); //erasing this will cause the shared_ptr to delete the stack -} - -LinkChannel* AsyncStackManager::GetChannelByStackName(const std::string& arStackName) -{ - StackToChannelMap::iterator i = mStackNameToChannel.find(arStackName); - if(i == mStackNameToChannel.end()) throw ArgumentException(LOCATION, "Unknown stack: " + arStackName); + StackMap::iterator i = mStackMap.find(arStackName); + if (i == mStackMap.end()) throw ArgumentException(LOCATION, "Unknown stack"); return i->second; } -Stack* AsyncStackManager::GetStackByName(const std::string& arStackName) -{ - StackMap::iterator i = mStackNameToStack.find(arStackName); - if (i == mStackNameToStack.end()) { - throw ArgumentException(LOCATION, "Unknown stack"); - } - - return i->second.get(); -} - void AsyncStackManager::ThrowIfAlreadyShutdown() { if(mIsShutdown) throw InvalidStateException(LOCATION, "Stack has been permanently shutdown"); @@ -333,15 +280,18 @@ LinkChannel* AsyncStackManager::CreateChannel(const std::string& arName) pChannelLogger->SetVarName(arName); AsyncTaskGroup* pGroup = mScheduler.CreateNewGroup(); - boost::shared_ptr pChannel(new LinkChannel(pChannelLogger, arName, &mTimerSrc, pPhys, pGroup, s.RetryTimeout)); + //boost::shared_ptr pChannel(new LinkChannel(pChannelLogger, arName, &mTimerSrc, pPhys, pGroup, s.RetryTimeout)); + LinkChannel* pChannel = new LinkChannel(pChannelLogger, arName, &mTimerSrc, pPhys, pGroup, s.RetryTimeout); mChannelNameToChannel[arName] = pChannel; - return pChannel.get(); + //return pChannel.get(); + return pChannel; } LinkChannel* AsyncStackManager::GetChannelMaybeNull(const std::string& arName) { ChannelToChannelMap::iterator i = mChannelNameToChannel.find(arName); - return (i == mChannelNameToChannel.end()) ? NULL : i->second.get(); + //return (i == mChannelNameToChannel.end()) ? NULL : i->second.get(); + return (i == mChannelNameToChannel.end()) ? NULL : i->second; } void AsyncStackManager::Run() @@ -361,17 +311,33 @@ void AsyncStackManager::Run() mService.Get()->reset(); } -void AsyncStackManager::OnAddStack(const std::string& arStackName, boost::shared_ptr apStack, LinkChannel* apChannel, const LinkRoute& arRoute) -{ +Stack* AsyncStackManager::SeverStackFromChannel(const std::string& arStackName) +{ + StackMap::iterator i = mStackMap.find(arStackName); + if(i == mStackMap.end()) throw ArgumentException(LOCATION, "Stack not found: " + arStackName); + + StackRecord rec = i->second; + mStackMap.erase(i); + + LOG_BLOCK(LEV_DEBUG, "Begin severing stack: " << arStackName); + { + Transaction tr(&mSuspendTimerSource); //need to pause execution so that this action is safe + rec.channel->RemoveStackFromChannel(arStackName); + } + LOG_BLOCK(LEV_DEBUG, "Done severing stack: " << arStackName); + return rec.stack; +} + +void AsyncStackManager::AddStackToChannel(const std::string& arStackName, Stack* apStack, LinkChannel* apChannel, const LinkRoute& arRoute) +{ { // when binding the stack to the router, we need to pause excution Transaction tr(&mSuspendTimerSource); - apChannel->BindStackToChannel(arStackName, apStack.get(), arRoute); + apChannel->BindStackToChannel(arStackName, apStack, arRoute); } - mStackNameToChannel[arStackName] = apChannel; // map the stack name to a LinkChannel object - mStackNameToStack[arStackName] = apStack; // map the stack name to a Stack object + mStackMap[arStackName] = StackRecord(apStack, apChannel); } } diff --git a/DNP3/AsyncStackManager.h b/DNP3/AsyncStackManager.h index d4bbd445..2800dc1e 100644 --- a/DNP3/AsyncStackManager.h +++ b/DNP3/AsyncStackManager.h @@ -22,7 +22,6 @@ #include #include -#include #include #include @@ -261,6 +260,7 @@ class AsyncStackManager : private Threadable, private Loggable } private: + IOService mService; TimerSourceASIO mTimerSrc; SuspendTimerSource mSuspendTimerSource; @@ -273,33 +273,41 @@ class AsyncStackManager : private Threadable, private Loggable void ThrowIfAlreadyShutdown(); - typedef std::map > StackMap; - StackMap mStackNameToStack; // maps a stack name a Stack instance + struct StackRecord { + StackRecord() : + stack(NULL), channel(NULL) + {} + + StackRecord(Stack* apStack, LinkChannel* apChannel) : + stack(apStack), channel(apChannel) + {} + + Stack* stack; + LinkChannel* channel; + }; - typedef std::map StackToChannelMap; - typedef std::map > ChannelToChannelMap; - StackToChannelMap mStackNameToChannel; // maps a stack name a channel instance - ChannelToChannelMap mChannelNameToChannel; // maps a channel name to a channel instance + typedef std::map StackMap; // maps a stack name the stack and it's channel + StackMap mStackMap; + + typedef std::map ChannelToChannelMap; + ChannelToChannelMap mChannelNameToChannel; // maps a channel name to a channel instance LinkChannel* GetOrCreateChannel(const std::string& arName); LinkChannel* GetChannelOrExcept(const std::string& arName); LinkChannel* GetChannelMaybeNull(const std::string& arName); LinkChannel* CreateChannel(const std::string& arName); - LinkChannel* GetChannelByStackName(const std::string& arStackName); - Stack* GetStackByName(const std::string& arStackName); + + StackRecord GetStackRecordByName(const std::string& arName); void Run(); - // Remove a stack - void SeverStack(LinkChannel* apChannel, const std::string& arStackName); - - void OnAddStack(const std::string& arStackName, boost::shared_ptr apStack, LinkChannel* apChannel, const LinkRoute&); + // Remove a stack, be responsible for it's deletion + Stack* SeverStackFromChannel(const std::string& arStackName); + void AddStackToChannel(const std::string& arStackName, Stack* apStack, LinkChannel* apChannel, const LinkRoute& arRoute); size_t NumStacks() { - return mStackNameToChannel.size(); - } - - std::vector StacksOnChannel(const std::string& arChannelName); + return mStackMap.size(); + } static void NullActionForInfiniteTimer() {} diff --git a/DNP3/DNP3.vcproj b/DNP3/DNP3.vcproj index e3e5692d..48dbef8a 100644 --- a/DNP3/DNP3.vcproj +++ b/DNP3/DNP3.vcproj @@ -17,7 +17,7 @@ diff --git a/DNP3/LinkChannel.cpp b/DNP3/LinkChannel.cpp index 2beed367..dfe79d21 100755 --- a/DNP3/LinkChannel.cpp +++ b/DNP3/LinkChannel.cpp @@ -25,6 +25,7 @@ #include #include #include +#include namespace apl { @@ -60,5 +61,10 @@ void LinkChannel::RemoveStackFromChannel(const std::string& arStackName) } } +std::vector LinkChannel::StacksOnChannel() +{ + return GetKeys(mStackMap); +} + } } diff --git a/DNP3/LinkChannel.h b/DNP3/LinkChannel.h index 3e653eee..adff0bb6 100755 --- a/DNP3/LinkChannel.h +++ b/DNP3/LinkChannel.h @@ -55,10 +55,11 @@ class LinkChannel : private LinkLayerRouter public: - LinkChannel(Logger* apLogger, const std::string& arName, ITimerSource* apTimerSrc, IPhysicalLayerAsync* apPhys, AsyncTaskGroup* apTaskGroup, millis_t aOpenRetry); + LinkChannel(Logger* apLogger, const std::string& arName, ITimerSource* apTimerSrc, IPhysicalLayerAsync* apPhys, AsyncTaskGroup* apTaskGroup, millis_t aOpenRetry); void BindStackToChannel(const std::string& arStackName, Stack* apStack, const LinkRoute& arRoute); void RemoveStackFromChannel(const std::string& arStackName); + std::vector StacksOnChannel(); std::string Name() { return mName; diff --git a/DNP3/LinkLayerRouter.cpp b/DNP3/LinkLayerRouter.cpp index d3f9e967..7a1f7597 100644 --- a/DNP3/LinkLayerRouter.cpp +++ b/DNP3/LinkLayerRouter.cpp @@ -69,14 +69,21 @@ void LinkLayerRouter::AddContext(ILinkContext* apContext, const LinkRoute& arRou void LinkLayerRouter::RemoveContext(const LinkRoute& arRoute) { AddressMap::iterator i = mAddressMap.find(arRoute); - if(i != mAddressMap.end()) { + if(i == mAddressMap.end()) throw ArgumentException(LOCATION, "LinkRoute not bound: " + arRoute.ToString()); + else { + ILinkContext* pContext = i->second; mAddressMap.erase(i); + if(this->GetState() == PLS_OPEN) pContext->OnLowerLayerDown(); + + // if no stacks are bound, suspend the router + if(mAddressMap.size() == 0) { + this->Suspend(); + } } - // if no stacks are bound, suspend the router - if(mAddressMap.size() == 0) this->Suspend(); + } ILinkContext* LinkLayerRouter::GetContext(const LinkRoute& arRoute) @@ -229,7 +236,6 @@ void LinkLayerRouter::OnPhysicalLayerCloseCallback() for(AddressMap::iterator i = mAddressMap.begin(); i != mAddressMap.end(); ++i) { i->second->OnLowerLayerDown(); } - } } diff --git a/DNP3/LinkRoute.cpp b/DNP3/LinkRoute.cpp index a6d55c10..2c089807 100644 --- a/DNP3/LinkRoute.cpp +++ b/DNP3/LinkRoute.cpp @@ -19,6 +19,8 @@ #include "LinkRoute.h" +#include + namespace apl { namespace dnp @@ -41,6 +43,13 @@ bool LinkRoute::LessThan::operator ()(const LinkRoute& a, const LinkRoute& b) co else return a.local < b.local; } +std::string LinkRoute::ToString() const +{ + std::ostringstream oss; + oss << *this; + return oss.str(); +} + std::ostream& operator<<(std::ostream& oss, const LinkRoute& arRoute) { return oss << " Local: " << arRoute.local << " Remote: " << arRoute.remote; diff --git a/DNP3/LinkRoute.h b/DNP3/LinkRoute.h index 7366c8c9..0600c810 100644 --- a/DNP3/LinkRoute.h +++ b/DNP3/LinkRoute.h @@ -52,6 +52,8 @@ class LinkRoute // Const to fix VS compilation bug bool operator()(const LinkRoute& a, const LinkRoute& b) const; }; + + std::string ToString() const; }; std::ostream& operator<<(std::ostream& oss, const LinkRoute&); diff --git a/DNP3Test/ComparingDataObserver.cpp b/DNP3Test/ComparingDataObserver.cpp new file mode 100755 index 00000000..e4100a70 --- /dev/null +++ b/DNP3Test/ComparingDataObserver.cpp @@ -0,0 +1,119 @@ +// +// Licensed to Green Energy Corp (www.greenenergycorp.com) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. Green Enery Corp licenses this file +// to you 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 "ComparingDataObserver.h" + +namespace apl +{ + +namespace dnp +{ + +ComparingDataObserver::ComparingDataObserver(Logger* apLogger, FlexibleDataObserver* apObserver) : + Loggable(apLogger), + mSameData(false), + mpObserver(apObserver) +{ + +} + +void ComparingDataObserver::Reset() +{ + CriticalSection cs(&mLock); + mBinaryMap.clear(); + mAnalogMap.clear(); + mCounterMap.clear(); + mControlStatusMap.clear(); + mSetpointStatusMap.clear(); + mSameData = false; +} + +bool ComparingDataObserver::IsSameData() +{ + size_t required = mpObserver->mBinaryMap.size() + + mpObserver->mAnalogMap.size() + + mpObserver->mCounterMap.size(); + + size_t actual = mBinaryMap.size() + + mAnalogMap.size() + + mCounterMap.size(); + + LOG_BLOCK(LEV_EVENT, actual << " of " << required); + + return (required == actual); + +} + +bool ComparingDataObserver::WaitForSameData(millis_t aWaitMs) +{ + CriticalSection cs(&mLock); + if(!mSameData) cs.TimedWait(aWaitMs); + return mSameData; +} + +void ComparingDataObserver::DescribeMissingData() +{ + this->DescribeAny(mpObserver->mBinaryMap, mBinaryMap); + this->DescribeAny(mpObserver->mAnalogMap, mAnalogMap); + this->DescribeAny(mpObserver->mCounterMap, mCounterMap); +} + +void ComparingDataObserver::_Start() +{ + mLock.Lock(); +} + +void ComparingDataObserver::_End() +{ + if(this->IsSameData()) { + mSameData = true; + mLock.Broadcast(); + } + mLock.Unlock(); + +} + +void ComparingDataObserver::_Update(const Binary& arPoint, size_t aIndex) +{ + this->UpdateAny(arPoint, aIndex, mpObserver->mBinaryMap, mBinaryMap); +} + +void ComparingDataObserver::_Update(const Analog& arPoint, size_t aIndex) +{ + this->UpdateAny(arPoint, aIndex, mpObserver->mAnalogMap, mAnalogMap); +} + +void ComparingDataObserver::_Update(const Counter& arPoint, size_t aIndex) +{ + this->UpdateAny(arPoint, aIndex, mpObserver->mCounterMap, mCounterMap); +} + +void ComparingDataObserver::_Update(const ControlStatus& arPoint, size_t aIndex) +{ + this->UpdateAny(arPoint, aIndex, mpObserver->mControlStatusMap, mControlStatusMap); +} + +void ComparingDataObserver::_Update(const SetpointStatus& arPoint, size_t aIndex) +{ + this->UpdateAny(arPoint, aIndex, mpObserver->mSetpointStatusMap, mSetpointStatusMap); +} + +} + +} + diff --git a/DNP3Test/ComparingDataObserver.h b/DNP3Test/ComparingDataObserver.h new file mode 100755 index 00000000..9d3d9356 --- /dev/null +++ b/DNP3Test/ComparingDataObserver.h @@ -0,0 +1,113 @@ +// +// Licensed to Green Energy Corp (www.greenenergycorp.com) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. Green Enery Corp licenses this file +// to you 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. +// +#ifndef __COMPARING_DATA_OBSERVER_H_ +#define __COMPARING_DATA_OBSERVER_H_ + +#include +#include +#include +#include +#include + +#include + +namespace apl +{ + +namespace dnp +{ + +class ComparingDataObserver : public apl::IDataObserver, private Loggable +{ +public: + + ComparingDataObserver(Logger* apLogger, FlexibleDataObserver* apObserver); + + void Reset(); + + bool WaitForSameData(millis_t aWaitMs); + + void DescribeMissingData(); + +private: + + bool mSameData; + + bool IsSameData(); + + SigLock mLock; + FlexibleDataObserver* mpObserver; + + typedef std::map CompareMap; + + CompareMap mBinaryMap; + CompareMap mAnalogMap; + CompareMap mCounterMap; + CompareMap mControlStatusMap; + CompareMap mSetpointStatusMap; + + void _Start(); + void _End(); + + void _Update(const Binary& arPoint, size_t aIndex); + void _Update(const Analog& arPoint, size_t aIndex); + void _Update(const Counter& arPoint, size_t aIndex); + void _Update(const ControlStatus& arPoint, size_t aIndex); + void _Update(const SetpointStatus& arPoint, size_t aIndex); + + template + void UpdateAny(const T& arPoint, size_t aIndex, const typename PointMap::Type& arMap, CompareMap& arCompareMap); + + template + void DescribeAny(const typename PointMap::Type& arMap, const CompareMap& arCompareMap); +}; + + +template +void ComparingDataObserver::DescribeAny(const typename PointMap::Type& arMap, const CompareMap& arCompareMap) +{ + for(PointMap::Type::const_iterator i = arMap.begin(); i != arMap.end(); ++i) { + CompareMap::const_iterator j = arCompareMap.find(i->first); + if(j == arCompareMap.end()) { + LOG_BLOCK(LEV_EVENT, "Missing: " << i->first << " - " << i->second.ToString()); + } + } +} + +template +void ComparingDataObserver::UpdateAny(const T& arPoint, size_t aIndex, const typename PointMap::Type& arMap, CompareMap& arCompareMap) +{ + PointMap::Type::const_iterator i = arMap.find(aIndex); + if(i == arMap.end()) { + LOG_BLOCK(LEV_ERROR, "Unexpected index: " << aIndex << " - " << arPoint.ToString()); + } + else { + if(i->second == arPoint) { + arCompareMap[aIndex] = true; + } + else arCompareMap.erase(aIndex); + } +} + +} + +} + +#endif + diff --git a/DNP3Test/DNP3Test.vcproj b/DNP3Test/DNP3Test.vcproj index f0a1cfa9..1db92869 100644 --- a/DNP3Test/DNP3Test.vcproj +++ b/DNP3Test/DNP3Test.vcproj @@ -307,6 +307,14 @@ + + + + diff --git a/DNP3Test/IntegrationTest.cpp b/DNP3Test/IntegrationTest.cpp index 814b6314..d76d57bd 100644 --- a/DNP3Test/IntegrationTest.cpp +++ b/DNP3Test/IntegrationTest.cpp @@ -42,77 +42,119 @@ using namespace std; using namespace apl; using namespace apl::dnp; -IntegrationTest::IntegrationTest(Logger* apLogger, FilterLevel aLevel, boost::uint16_t aStartPort, size_t aNumPairs, size_t aNumPoints) : - AsyncTestObjectASIO(), - M_START_PORT(aStartPort), - mChange(false), - mNotifier(boost::bind(&IntegrationTest::RegisterChange, this)), - mManager(apLogger) +IntegrationTest::IntegrationTest(Logger* apLogger, FilterLevel aLevel, boost::uint16_t aStartPort, size_t aNumPairs, size_t aNumPoints) : + Loggable(apLogger), + M_START_PORT(aStartPort), + mManager(apLogger), + NUM_POINTS(aNumPoints) { + this->InitLocalObserver(); + for (size_t i = 0; i < aNumPairs; ++i) { AddStackPair(aLevel, aNumPoints); } - mFanout.Add(&mLocalFDO); + mFanout.AddObserver(&mLocalFDO); } -void IntegrationTest::RegisterChange() +void IntegrationTest::InitLocalObserver() { - mChange = true; + Transaction tr(&mLocalFDO); + for (size_t i = 0; i < NUM_POINTS; ++i) { + mLocalFDO.Update(this->RandomBinary(), i); + mLocalFDO.Update(this->RandomAnalog(), i); + mLocalFDO.Update(this->RandomCounter(), i); + } } -bool IntegrationTest::SameData() +void IntegrationTest::ResetObservers() { - if(!mChange) return false; - else { + for (size_t i = 0; i < this->mMasterObservers.size(); ++i) { + mMasterObservers[i]->Reset(); + } +} - mChange = false; +bool IntegrationTest::WaitForSameData(millis_t aTimeout, bool aDescribeAnyMissingData) +{ + LOG_BLOCK(LEV_EVENT, "Wait for same data"); - BOOST_FOREACH(boost::shared_ptr pObs, mMasterObservers) { - Transaction tr(pObs.get()); - if(!FlexibleDataObserver::StrictEquality(*(pObs.get()), mLocalFDO)) return false; + for (size_t i = 0; i < this->mMasterObservers.size(); ++i) { + ComparingDataObserver* pObs = mMasterObservers[i].get(); + if(!pObs->WaitForSameData(aTimeout)) { + if(aDescribeAnyMissingData) pObs->DescribeMissingData(); + return false; } - - return true; } + + return true; +} + +void IntegrationTest::IncrementData() +{ + LOG_BLOCK(LEV_EVENT, "Incrementing data"); + + this->ResetObservers(); + /* + * Resource Acquisition Is Initialization (RAII) Pattern. + * When the Transaction instance is created, it acquires the resource. + * When it is destroyed, it releases the resource. The scoping using + * the {} block forces destruction of the Transaction at the right time. + */ + Transaction tr(&mFanout); + for (size_t i = 0; i < NUM_POINTS; ++i) { + mFanout.Update(this->Next(mLocalFDO.mBinaryMap[i]), i); + mFanout.Update(this->Next(mLocalFDO.mAnalogMap[i]), i); + mFanout.Update(this->Next(mLocalFDO.mCounterMap[i]), i); + } } Binary IntegrationTest::RandomBinary() { - boost::uniform_int<> num(0, 1); - boost::variate_generator > val(rng, num); - Binary v(val() ? true : false, BQ_ONLINE); + Binary v(mRandomBool.NextBool(), BQ_ONLINE); return v; } Analog IntegrationTest::RandomAnalog() -{ - boost::uniform_int num; - boost::variate_generator > val(rng, num); - Analog v(val(), AQ_ONLINE); +{ + Analog v(mRandomInt32.Next(), AQ_ONLINE); return v; } Counter IntegrationTest::RandomCounter() -{ - boost::uniform_int num; - boost::variate_generator > val(rng, num); - Counter v(val(), CQ_ONLINE); +{ + Counter v(mRandomUInt32.Next(), CQ_ONLINE); return v; } +Binary IntegrationTest::Next(const Binary& arPoint) +{ + Binary point(!arPoint.GetValue(), arPoint.GetQuality()); + return point; +} + +Analog IntegrationTest::Next(const Analog& arPoint) +{ + Analog point(arPoint.GetValue()+1, arPoint.GetQuality()); + return point; +} + +Counter IntegrationTest::Next(const Counter& arPoint) +{ + Counter point(arPoint.GetValue()+1, arPoint.GetQuality()); + return point; +} + void IntegrationTest::AddStackPair(FilterLevel aLevel, size_t aNumPoints) { boost::uint16_t port = M_START_PORT + static_cast(this->mMasterObservers.size()); - boost::shared_ptr pMasterFDO(new FlexibleDataObserver()); - mMasterObservers.push_back(pMasterFDO); - pMasterFDO->AddObserver(&mNotifier); - ostringstream oss; oss << "Port: " << port; std::string client = oss.str() + " Client "; std::string server = oss.str() + " Server "; + boost::shared_ptr pMasterFDO(new ComparingDataObserver(mpLogger->GetSubLogger(client), &mLocalFDO)); + mMasterObservers.push_back(pMasterFDO); + PhysLayerSettings s(aLevel, 1000); this->mManager.AddTCPClient(client, s, "127.0.0.1", port); this->mManager.AddTCPServer(server, s, "127.0.0.1", port); @@ -144,7 +186,7 @@ void IntegrationTest::AddStackPair(FilterLevel aLevel, size_t aNumPoints) cfg.slave.mUnsolPackDelay = 0; cfg.device = DeviceTemplate(aNumPoints, aNumPoints, aNumPoints); IDataObserver* pObs = this->mManager.AddSlave(server, server, aLevel, &mCmdAcceptor, cfg); - this->mFanout.Add(pObs); + this->mFanout.AddObserver(pObs); } } diff --git a/DNP3Test/IntegrationTest.h b/DNP3Test/IntegrationTest.h index 3cd0f1fa..2332f56c 100644 --- a/DNP3Test/IntegrationTest.h +++ b/DNP3Test/IntegrationTest.h @@ -19,113 +19,79 @@ #ifndef __INTEGRATION_TEST_H_ #define __INTEGRATION_TEST_H_ -#include -#include #include #include #include +#include +#include + +#include +#include + #include -#include -#include -#include -#include +#include "ComparingDataObserver.h" + +#include +#include #include #include -namespace boost -{ -namespace asio -{ -class io_service; -} -} - namespace apl { namespace dnp { -class ObserverFanout : public IDataObserver +class IntegrationTest : private Loggable { public: - void Add(IDataObserver* apObserver) { - mObservers.push_back(apObserver); - } - - void _Start() { - mBuffer.Start(); - } - void _End() { - mBuffer.End(); - - BOOST_FOREACH(IDataObserver * p, mObservers) { - mBuffer.FlushUpdates(p, false); - } + IntegrationTest(Logger* apLogger, FilterLevel aLevel, boost::uint16_t aStartPort, size_t aNumPairs, size_t aNumPoints); - Transaction tr(&mBuffer); mBuffer.Clear(); + IDataObserver* GetFanout() { + return &mFanout; } - void _Update(const Binary& arPoint, size_t aIndex) { - mBuffer.Update(arPoint, aIndex); - } - void _Update(const Analog& arPoint, size_t aIndex) { - mBuffer.Update(arPoint, aIndex); - } - void _Update(const Counter& arPoint, size_t aIndex) { - mBuffer.Update(arPoint, aIndex); - } - void _Update(const ControlStatus& arPoint, size_t aIndex) { - mBuffer.Update(arPoint, aIndex); - } - void _Update(const SetpointStatus& arPoint, size_t aIndex) { - mBuffer.Update(arPoint, aIndex); - } + void IncrementData(); + + bool WaitForSameData(millis_t aTimeout, bool aDescribeAnyMissingData); + + AsyncStackManager* GetManager() { + return &mManager; + } private: - ChangeBuffer mBuffer; - std::vector mObservers; - -}; -class IntegrationTest : public AsyncTestObjectASIO -{ -public: + void InitLocalObserver(); - IntegrationTest(Logger* apLogger, FilterLevel aLevel, boost::uint16_t aStartPort, size_t aNumPairs, size_t aNumPoints); - - IDataObserver* GetFanout() { - return &mFanout; - } - - bool SameData(); + void ResetObservers(); Binary RandomBinary(); Analog RandomAnalog(); Counter RandomCounter(); - AsyncStackManager* GetManager() { - return &mManager; - } - -private: + Binary Next(const Binary& arPoint); + Analog Next(const Analog& arPoint); + Counter Next(const Counter& arPoint); + void RegisterChange(); void AddStackPair(FilterLevel aLevel, size_t aNumPoints); - std::vector< boost::shared_ptr > mMasterObservers; - ObserverFanout mFanout; - const boost::uint16_t M_START_PORT; - Logger* mpLogger; + std::vector< boost::shared_ptr > mMasterObservers; + FanoutDataObserver mFanout; - bool mChange; - BoundNotifier mNotifier; + Random mRandomInt32; + Random mRandomUInt32; + RandomBool mRandomBool; + + const boost::uint16_t M_START_PORT; + FlexibleDataObserver mLocalFDO; MockCommandAcceptor mCmdAcceptor; - boost::mt19937 rng; //random number generator AsyncStackManager mManager; + size_t NUM_POINTS; }; } diff --git a/DNP3Test/TestIntegration.cpp b/DNP3Test/TestIntegration.cpp index bc835c73..5c81b30b 100644 --- a/DNP3Test/TestIntegration.cpp +++ b/DNP3Test/TestIntegration.cpp @@ -25,7 +25,7 @@ #include "IntegrationTest.h" -#define EXTRA_DEBUG (0) +#define OUTPUT_PERF_NUMBERS (0) using namespace apl; using namespace apl::dnp; @@ -55,48 +55,27 @@ const boost::uint16_t START_PORT = MACRO_PORT_START; const size_t NUM_PAIRS = MACRO_NUM_PAIRS; const size_t NUM_POINTS = 500; const size_t NUM_CHANGES = 10; +const FilterLevel FILTER_LEVEL = LEV_WARNING; BOOST_AUTO_TEST_CASE(MasterToSlaveThroughput) { EventLog log; //LogToStdio::Inst()->SetPrintLocation(true); - //log.AddLogSubscriber(LogToStdio::Inst()); + //log.AddLogSubscriber(LogToStdio::Inst()); - IntegrationTest t(log.GetLogger(LEV_INFO, "test"), LEV_INFO, START_PORT, + IntegrationTest t(log.GetLogger(FILTER_LEVEL, "test"), FILTER_LEVEL, START_PORT, NUM_PAIRS, NUM_POINTS); - IDataObserver* pObs = t.GetFanout(); StopWatch sw; for (size_t j = 0; j < NUM_CHANGES; ++j) { - /* - * Resource Acquisition Is Initialization (RAII) Pattern. - * When the Transaction instance is created, it acquires the resource. - * When it is destroyed, it releases the resource. The scoping using - * the {} block forces destruction of the Transaction at the right time. - */ - { - Transaction tr(pObs); - - for (size_t i = 0; i < NUM_POINTS; ++i) - pObs->Update(t.RandomBinary(), i); - - for (size_t i = 0; i < NUM_POINTS; ++i) - pObs->Update(t.RandomAnalog(), i); - - for (size_t i = 0; i < NUM_POINTS; ++i) - pObs->Update(t.RandomCounter(), i); - } + t.IncrementData(); + BOOST_REQUIRE(t.WaitForSameData(20000, true)); + } - BOOST_REQUIRE(t.ProceedUntil(boost::bind(&IntegrationTest::SameData, &t))); - - if (EXTRA_DEBUG) - cout << "*** Finished change set " << j << " ***" << endl; - } - - if (EXTRA_DEBUG) { + if (OUTPUT_PERF_NUMBERS) { double elapsed_sec = sw.Elapsed() / 1000.0; size_t points = 3 * NUM_POINTS * NUM_CHANGES * NUM_PAIRS * 2; cout << "num points: " << points << endl; @@ -109,9 +88,8 @@ BOOST_AUTO_TEST_CASE(MasterToSlaveThroughput) // TODO - Factor this test into smaller tests BOOST_AUTO_TEST_CASE(IntegrationTestConstructionDestruction) { - EventLog log; - if (EXTRA_DEBUG) - log.AddLogSubscriber(LogToStdio::Inst()); + EventLog log; + //log.AddLogSubscriber(LogToStdio::Inst()); IntegrationTest t(log.GetLogger(LEV_WARNING, "test"), LEV_WARNING, START_PORT, NUM_PAIRS, NUM_POINTS); diff --git a/Terminal/FlexibleObserverTerminalExtension.cpp b/Terminal/FlexibleObserverTerminalExtension.cpp index 37ad6017..28ced99c 100755 --- a/Terminal/FlexibleObserverTerminalExtension.cpp +++ b/Terminal/FlexibleObserverTerminalExtension.cpp @@ -106,10 +106,10 @@ void FlexibleObserverTerminalExtension::_BindToTerminal(ITerminal* apTerminal) } template -void DisplayPoints(ostringstream& arOss, typename FlexibleDataObserver::PointMap::Type& arMap, FlexibleObserverTerminalExtension::NameMap aNameMap, const char* arTitle, const ShowRange& aRange, size_t aLongestName) +void DisplayPoints(ostringstream& arOss, typename PointMap::Type& arMap, FlexibleObserverTerminalExtension::NameMap aNameMap, const char* arTitle, const ShowRange& aRange, size_t aLongestName) { - typename FlexibleDataObserver::PointMap::Type::iterator i = arMap.begin(); + typename PointMap::Type::iterator i = arMap.begin(); arOss << arTitle << ITerminal::EOL; From 6cf2a64f17f90dc579192dde5d0181659505eada Mon Sep 17 00:00:00 2001 From: jadamcrain Date: Thu, 14 Jul 2011 11:14:55 -0400 Subject: [PATCH 2/9] Fixed a broken test in PhysicalLayerMonitorSuite and added a test for the shutdown post --- APL/PhysicalLayerMonitor.cpp | 14 ++++++++++++-- APL/PhysicalLayerMonitor.h | 7 +++++-- TestAPL/TestPhysicalLayerMonitor.cpp | 16 +++++++++++++++- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/APL/PhysicalLayerMonitor.cpp b/APL/PhysicalLayerMonitor.cpp index 96a487f2..6498ca38 100755 --- a/APL/PhysicalLayerMonitor.cpp +++ b/APL/PhysicalLayerMonitor.cpp @@ -61,10 +61,20 @@ void PhysicalLayerMonitor::AddObserver(IPhysicalLayerObserver* apObserver) mObservers.insert(apObserver); } -void PhysicalLayerMonitor::WaitForShutdown() +bool PhysicalLayerMonitor::WaitForShutdown(millis_t aTimeoutMs) { CriticalSection cs(&mLock); - while(!mFinalShutdown) cs.Wait(); + + while(!mFinalShutdown) + { + if(aTimeoutMs < 0) cs.Wait(); + else { + cs.TimedWait(aTimeoutMs); + break; + } + } + + return mFinalShutdown; } void PhysicalLayerMonitor::ChangeState(IMonitorState* apState) diff --git a/APL/PhysicalLayerMonitor.h b/APL/PhysicalLayerMonitor.h index 2778ec97..df1b9d70 100755 --- a/APL/PhysicalLayerMonitor.h +++ b/APL/PhysicalLayerMonitor.h @@ -65,8 +65,11 @@ class PhysicalLayerMonitor : public IHandlerAsync /** Add an observer to the set of state callbacks */ void AddObserver(IPhysicalLayerObserver* apObserver); - /** Blocks until the monitor has completely and permanently stopped */ - void WaitForShutdown(); + /** Blocks until the monitor has permanently stopped or the timeout expires. + @param aTimeoutMS Timeout in milliseconds, < 0 waits forever + @return True of the shutdown condition was met, false otherwise + */ + bool WaitForShutdown(millis_t aTimeoutMs = -1); Logger* GetLogger() { return mpLogger; diff --git a/TestAPL/TestPhysicalLayerMonitor.cpp b/TestAPL/TestPhysicalLayerMonitor.cpp index e9696bba..5357de94 100755 --- a/TestAPL/TestPhysicalLayerMonitor.cpp +++ b/TestAPL/TestPhysicalLayerMonitor.cpp @@ -274,12 +274,26 @@ BOOST_AUTO_TEST_CASE(OpenFailureGoesToClosedIfSuspended) BOOST_REQUIRE_EQUAL(0, test.mts.NumActive()); } -BOOST_AUTO_TEST_CASE(StopWhileWaitingCancelsTimer) +BOOST_AUTO_TEST_CASE(ShutdownPostsToTimer) +{ + TestObject test; + BOOST_REQUIRE_EQUAL(0, test.mts.NumActive()); + BOOST_REQUIRE_FALSE(test.monitor.WaitForShutdown(0)); + test.monitor.Shutdown(); + BOOST_REQUIRE_EQUAL(PLS_SHUTDOWN, test.monitor.GetState()); + BOOST_REQUIRE_EQUAL(1, test.mts.NumActive()); + BOOST_REQUIRE_FALSE(test.monitor.WaitForShutdown(0)); + BOOST_REQUIRE(test.mts.DispatchOne()); + BOOST_REQUIRE(test.monitor.WaitForShutdown()); //wait indefinitely, but it's already shutdown +} + +BOOST_AUTO_TEST_CASE(ShutdownWhileWaitingCancelsTimer) { TestObject test; test.monitor.Start(); test.phys.SignalOpenFailure(); test.monitor.Shutdown(); + BOOST_REQUIRE(test.mts.DispatchOne()); //disptach the shutdown post BOOST_REQUIRE_EQUAL(PLS_SHUTDOWN, test.monitor.GetState()); BOOST_REQUIRE_EQUAL(0, test.mts.NumActive()); } From cd8c4f7dd4d553be1302ae4fa2c22d7c0c9bbe63 Mon Sep 17 00:00:00 2001 From: jadamcrain Date: Thu, 14 Jul 2011 13:29:43 -0400 Subject: [PATCH 3/9] StartsOnClose no publishes PLS_CLOSED state gain before PLS_OPENING. ITimerSource::StartInfinite is bound to a static function and now longer requires an argument --- APL/PhysicalLayerMonitorStates.cpp | 4 ++-- APL/TimerInterfaces.h | 11 ++++++++--- DNP3/AsyncStackManager.cpp | 2 +- DNP3/AsyncStackManager.h | 8 ++++---- DNP3Test/TestVtoOnewayIntegration.cpp | 11 ++++++----- SlaveDemo/SlaveDemo.cpp | 8 +++----- SlaveDemo/SlaveDemo.h | 3 --- 7 files changed, 24 insertions(+), 23 deletions(-) diff --git a/APL/PhysicalLayerMonitorStates.cpp b/APL/PhysicalLayerMonitorStates.cpp index 285b663b..03b54bd1 100755 --- a/APL/PhysicalLayerMonitorStates.cpp +++ b/APL/PhysicalLayerMonitorStates.cpp @@ -110,8 +110,8 @@ void IgnoresSuspend::OnSuspendRequest(PhysicalLayerMonitor* apContext) void StartsOnClose::OnLayerClose(PhysicalLayerMonitor* apContext) { - MonitorStateActions::ChangeState(apContext, MonitorStateOpening::Inst()); - MonitorStateActions::AsyncOpen(apContext); + MonitorStateActions::ChangeState(apContext, MonitorStateSuspended::Inst()); + apContext->Start(); } /* --- IgnoresShutdown --- */ diff --git a/APL/TimerInterfaces.h b/APL/TimerInterfaces.h index dd569226..7b9f4295 100644 --- a/APL/TimerInterfaces.h +++ b/APL/TimerInterfaces.h @@ -23,6 +23,7 @@ #include "Types.h" #include "TimeTypes.h" #include +#include #include namespace apl @@ -72,11 +73,11 @@ typedef boost::function ExpirationHandler; class ITimerSource { public: - virtual ~ITimerSource() {} + virtual ~ITimerSource() {} - ITimer* StartInfinite(const ExpirationHandler& arHandler) { + ITimer* StartInfinite() { boost::posix_time::ptime t(boost::date_time::max_date_time); - return this->Start(t, arHandler); + return this->Start(t, boost::bind(&ITimerSource::NullActionForInfiniteTimer)); } /** Returns a new timer based on a relative time */ @@ -87,6 +88,10 @@ class ITimerSource /** Thread-safe way to post an event to handled asynchronously */ virtual void Post(const ExpirationHandler&) = 0; + +private: + static void NullActionForInfiniteTimer() {} + }; } diff --git a/DNP3/AsyncStackManager.cpp b/DNP3/AsyncStackManager.cpp index 6162ca26..b751ccde 100644 --- a/DNP3/AsyncStackManager.cpp +++ b/DNP3/AsyncStackManager.cpp @@ -57,7 +57,7 @@ AsyncStackManager::AsyncStackManager(Logger* apLogger) : mScheduler(&mTimerSrc), mVtoManager(apLogger->GetSubLogger("vto"), &mTimerSrc, &mMgr), mThread(this), - mpInfiniteTimer(mTimerSrc.StartInfinite(boost::bind(&AsyncStackManager::NullActionForInfiniteTimer))), + mpInfiniteTimer(mTimerSrc.StartInfinite()), mIsShutdown(false) { mThread.Start(); diff --git a/DNP3/AsyncStackManager.h b/DNP3/AsyncStackManager.h index 2800dc1e..0a2b9112 100644 --- a/DNP3/AsyncStackManager.h +++ b/DNP3/AsyncStackManager.h @@ -301,15 +301,15 @@ class AsyncStackManager : private Threadable, private Loggable void Run(); - // Remove a stack, be responsible for it's deletion + // Remove and close a stack, but delegate responsibility for deletion Stack* SeverStackFromChannel(const std::string& arStackName); + + // Add a stack from to a specified channel void AddStackToChannel(const std::string& arStackName, Stack* apStack, LinkChannel* apChannel, const LinkRoute& arRoute); size_t NumStacks() { return mStackMap.size(); - } - - static void NullActionForInfiniteTimer() {} + } }; diff --git a/DNP3Test/TestVtoOnewayIntegration.cpp b/DNP3Test/TestVtoOnewayIntegration.cpp index bf560883..cb78c41c 100755 --- a/DNP3Test/TestVtoOnewayIntegration.cpp +++ b/DNP3Test/TestVtoOnewayIntegration.cpp @@ -74,7 +74,7 @@ BOOST_AUTO_TEST_SUITE(VtoOnewayIntegrationSuite) BOOST_AUTO_TEST_CASE(Reconnection) { - VtoOnewayTestStack stack(true, false, false); + VtoOnewayTestStack stack(true, true, false); // start up everything, the local side should be able to open stack.remote.Start(); @@ -84,21 +84,22 @@ BOOST_AUTO_TEST_CASE(Reconnection) for(size_t i = 0; i < 1; ++i) { - stack.Log(LOCATION, "Begin iteration"); + stack.Log(LOCATION, "Begin iteration - Waiting for both sides to open"); BOOST_REQUIRE(stack.WaitForBothSides(PLS_OPEN)); // test that data is correctly sent both ways + data.Randomize(); stack.local.ExpectData(data); stack.local.WriteData(data); + stack.Log(LOCATION, "Waiting for expected data"); BOOST_REQUIRE(stack.WaitForExpectedDataToBeReceived()); // close the remote loopback server, which will cause both sides to close and reopen stack.remote.Close(); - BOOST_REQUIRE(stack.WaitForBothSides(PLS_CLOSED)); - - stack.Log(LOCATION, "End iteration"); + stack.Log(LOCATION, "Waiting for both sides to close"); + BOOST_REQUIRE(stack.WaitForBothSides(PLS_CLOSED)); } } diff --git a/SlaveDemo/SlaveDemo.cpp b/SlaveDemo/SlaveDemo.cpp index 25ae913e..57b00816 100755 --- a/SlaveDemo/SlaveDemo.cpp +++ b/SlaveDemo/SlaveDemo.cpp @@ -29,11 +29,9 @@ namespace dnp SlaveDemoBase::SlaveDemoBase(Logger* apLogger) : IOService(), IOServiceThread(apLogger, this->Get()), - mTimerSource(this->Get()) -{ - // Start a timer that will do nothing but keep the boost asio service from returning when it has no work to do - mpInfiniteTimer = mTimerSource.StartInfinite(boost::bind(&SlaveDemoBase::Timeout, this)); - + mTimerSource(this->Get()), + mpInfiniteTimer(mTimerSource.StartInfinite()) +{ // Create a notifier that when called will post a call to OnCommandNotify INotifier* pNotifier = mPostSource.Get(boost::bind(&SlaveDemoBase::OnCommandNotify, this), &mTimerSource); diff --git a/SlaveDemo/SlaveDemo.h b/SlaveDemo/SlaveDemo.h index 7571f0f3..cce33b36 100755 --- a/SlaveDemo/SlaveDemo.h +++ b/SlaveDemo/SlaveDemo.h @@ -62,9 +62,6 @@ class SlaveDemoBase : protected ICommandHandler, private IOService, public IOSer causes a single command to be processed */ void OnCommandNotify(); - // Placeholder method for the boost timer system. - void Timeout() {} - // The CommandQueue object serves as a thread-safe cache and notification mechanism. It implements the // ICommandAcceptor/IResponseAcceptor/ICommandSource interface, which is used by the slave/application // during control sequences From 78cc93555f6cd0d159a45fb6b9116fd87466cd67 Mon Sep 17 00:00:00 2001 From: jadamcrain Date: Thu, 14 Jul 2011 15:45:19 -0400 Subject: [PATCH 4/9] Stabilized deletion/shutdown of vto routers --- APL/APL.vcproj | 20 +++++++-- APL/AsyncTaskGroup.cpp | 2 +- APL/DeleteAny.h | 38 ++++++++++++++++ APL/ITimer.h | 52 ++++++++++++++++++++++ APL/ITimerSource.cpp | 37 ++++++++++++++++ APL/{TimerInterfaces.h => ITimerSource.h} | 54 ++++++++--------------- APL/PhysicalLayerMonitor.h | 2 +- APL/PostingNotifier.h | 2 +- APL/PostingNotifierSource.h | 2 +- APL/SuspendTimerSource.cpp | 2 +- APL/TimerASIO.h | 2 +- APL/TimerSourceASIO.h | 2 +- APLTestTools/MockPhysicalLayerAsync.cpp | 2 +- APLTestTools/MockTimerSource.h | 2 +- DNP3/AppLayer.cpp | 2 +- DNP3/AppLayerChannel.cpp | 2 +- DNP3/AsyncStackManager.cpp | 26 +++++++---- DNP3/AsyncStackManager.h | 24 +++++----- DNP3/LinkLayer.h | 2 +- DNP3/Master.cpp | 2 +- DNP3/VtoRouterManager.cpp | 25 ++++++----- DNP3/VtoRouterManager.h | 26 ++++++----- DNP3Test/TestVtoOnewayIntegration.cpp | 2 +- DNP3Test/TransportStackPair.h | 2 +- Makefile.am | 2 +- Terminal/LogTerminalExtension.cpp | 2 +- Terminal/TerminalInterfaces.h | 21 ++++++++- 27 files changed, 257 insertions(+), 100 deletions(-) create mode 100755 APL/DeleteAny.h create mode 100644 APL/ITimer.h create mode 100755 APL/ITimerSource.cpp rename APL/{TimerInterfaces.h => ITimerSource.h} (62%) mode change 100644 => 100755 diff --git a/APL/APL.vcproj b/APL/APL.vcproj index 57b3647f..23a3fab5 100755 --- a/APL/APL.vcproj +++ b/APL/APL.vcproj @@ -540,6 +540,10 @@ RelativePath=".\Configure.h" > + + @@ -736,6 +740,18 @@ + + + + + + @@ -768,10 +784,6 @@ RelativePath=".\TimerASIO.h" > - - diff --git a/APL/AsyncTaskGroup.cpp b/APL/AsyncTaskGroup.cpp index ddf6ef64..0a313f58 100644 --- a/APL/AsyncTaskGroup.cpp +++ b/APL/AsyncTaskGroup.cpp @@ -25,7 +25,7 @@ #include "AsyncTaskScheduler.h" #include "Exception.h" -#include "TimerInterfaces.h" +#include "ITimerSource.h" #include #include diff --git a/APL/DeleteAny.h b/APL/DeleteAny.h new file mode 100755 index 00000000..4036115e --- /dev/null +++ b/APL/DeleteAny.h @@ -0,0 +1,38 @@ +// +// Licensed to Green Energy Corp (www.greenenergycorp.com) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. Green Enery Corp licenses this file +// to you 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. +// + +#ifndef __DELETE_ANY_H_ +#define __DELETE_ANY_H_ + +#include + +namespace apl +{ + +/** Useful for posting to a timer source */ +template +void DeleteAny(const T* apType) +{ + delete apType; +} + +} + +#endif + diff --git a/APL/ITimer.h b/APL/ITimer.h new file mode 100644 index 00000000..2ce6d408 --- /dev/null +++ b/APL/ITimer.h @@ -0,0 +1,52 @@ +// +// Licensed to Green Energy Corp (www.greenenergycorp.com) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. Green Enery Corp licenses this file +// to you 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. +// +#ifndef __I_TIMER_H_ +#define __I_TIMER_H_ + +#include + +namespace apl +{ + +/** + * This is a wrapper for ASIO timers that are used to post events + * on a queue. Events can be posted for immediate consumption or + * some time in the future. Events can be consumbed by the posting + * thread or another thread. + * + * @section Class Goals + * + * Decouple APL code form ASIO so ASIO could be replace if need be. + * + * There is a problem with ASIO. When cancel is called, an event is + * posted. We wanted a cancel that does not generate any events. + * + * @see TimerASIO + */ +class ITimer +{ +public: + virtual ~ITimer() {} + virtual void Cancel() = 0; + virtual boost::posix_time::ptime ExpiresAt() = 0; +}; + +} + +#endif diff --git a/APL/ITimerSource.cpp b/APL/ITimerSource.cpp new file mode 100755 index 00000000..ead91ad5 --- /dev/null +++ b/APL/ITimerSource.cpp @@ -0,0 +1,37 @@ +// +// Licensed to Green Energy Corp (www.greenenergycorp.com) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. Green Enery Corp licenses this file +// to you 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 "ITimerSource.h" + +#include + +namespace apl +{ + +ITimer* ITimerSource::StartInfinite() +{ + boost::posix_time::ptime t(boost::date_time::max_date_time); + return this->Start(t, boost::bind(&ITimerSource::NullActionForInfiniteTimer)); +} + +void ITimerSource::NullActionForInfiniteTimer() +{ + +} + +} diff --git a/APL/TimerInterfaces.h b/APL/ITimerSource.h old mode 100644 new mode 100755 similarity index 62% rename from APL/TimerInterfaces.h rename to APL/ITimerSource.h index 7b9f4295..ae3112cb --- a/APL/TimerInterfaces.h +++ b/APL/ITimerSource.h @@ -16,46 +16,21 @@ // specific language governing permissions and limitations // under the License. // -#ifndef __TIMER_INTERFACES_H_ -#define __TIMER_INTERFACES_H_ - +#ifndef __I_TIMER_SOURCE_H_ +#define __I_TIMER_SOURCE_H_ #include "Types.h" #include "TimeTypes.h" +#include "ITimer.h" +#include "DeleteAny.h" + #include -#include -#include namespace apl { -/** - * This is a wrapper for ASIO timers that are used to post events - * on a queue. Events can be posted for immediate consumption or - * some time in the future. Events can be consumbed by the posting - * thread or another thread. - * - * @section Class Goals - * - * Decouple APL code form ASIO so ASIO could be replace if need be. - * - * There is a problem with ASIO. When cancel is called, an event is - * posted. We wanted a cancel that does not generate any events. - * - * @see TimerASIO - */ -class ITimer -{ -public: - virtual ~ITimer() {} - virtual void Cancel() = 0; - virtual boost::posix_time::ptime ExpiresAt() = 0; -}; - -/** @section desc Parameterless signature for Expiration callbacks */ typedef boost::function ExpirationHandler; - /** * Interface for posting events to a queue. Events can be posted for * immediate consumption or some time in the future. Events can be consumbed @@ -75,10 +50,7 @@ class ITimerSource public: virtual ~ITimerSource() {} - ITimer* StartInfinite() { - boost::posix_time::ptime t(boost::date_time::max_date_time); - return this->Start(t, boost::bind(&ITimerSource::NullActionForInfiniteTimer)); - } + ITimer* StartInfinite(); /** Returns a new timer based on a relative time */ virtual ITimer* Start(millis_t, const ExpirationHandler&) = 0; @@ -89,11 +61,23 @@ class ITimerSource /** Thread-safe way to post an event to handled asynchronously */ virtual void Post(const ExpirationHandler&) = 0; + /** Delete any type via a Post */ + template + void DeleteViaPost(T* apType); + + private: - static void NullActionForInfiniteTimer() {} + static void NullActionForInfiniteTimer(); }; +/** Helper functions */ +template +void ITimerSource::DeleteViaPost(T* apType) +{ + this->Post(boost::bind(&DeleteAny, apType)); +} + } #endif diff --git a/APL/PhysicalLayerMonitor.h b/APL/PhysicalLayerMonitor.h index df1b9d70..da69e83b 100755 --- a/APL/PhysicalLayerMonitor.h +++ b/APL/PhysicalLayerMonitor.h @@ -21,7 +21,7 @@ #include "IHandlerAsync.h" -#include "TimerInterfaces.h" +#include "ITimerSource.h" #include "IPhysicalLayerObserver.h" #include diff --git a/APL/PostingNotifier.h b/APL/PostingNotifier.h index ef6b3a14..aa4f0b77 100644 --- a/APL/PostingNotifier.h +++ b/APL/PostingNotifier.h @@ -20,7 +20,7 @@ #define __POSTING_NOTIFIER_H_ #include "INotifier.h" -#include "TimerInterfaces.h" +#include "ITimerSource.h" namespace apl { diff --git a/APL/PostingNotifierSource.h b/APL/PostingNotifierSource.h index af1e15f0..76fe2eae 100644 --- a/APL/PostingNotifierSource.h +++ b/APL/PostingNotifierSource.h @@ -19,7 +19,7 @@ #ifndef __POSTING_NOTIFIER_SOURCE_H_ #define __POSTING_NOTIFIER_SOURCE_H_ -#include "TimerInterfaces.h" +#include "ITimerSource.h" #include #include diff --git a/APL/SuspendTimerSource.cpp b/APL/SuspendTimerSource.cpp index 02a0f7c5..c177f93f 100755 --- a/APL/SuspendTimerSource.cpp +++ b/APL/SuspendTimerSource.cpp @@ -19,7 +19,7 @@ #include "SuspendTimerSource.h" -#include "TimerInterfaces.h" +#include "ITimerSource.h" #include diff --git a/APL/TimerASIO.h b/APL/TimerASIO.h index 55b7c9b8..fcbdda6e 100644 --- a/APL/TimerASIO.h +++ b/APL/TimerASIO.h @@ -21,7 +21,7 @@ #include -#include "TimerInterfaces.h" +#include "ITimerSource.h" namespace apl { diff --git a/APL/TimerSourceASIO.h b/APL/TimerSourceASIO.h index 0839890e..60de4adb 100644 --- a/APL/TimerSourceASIO.h +++ b/APL/TimerSourceASIO.h @@ -19,7 +19,7 @@ #ifndef __TIMER_SOURCE_ASIO_H_ #define __TIMER_SOURCE_ASIO_H_ -#include "TimerInterfaces.h" +#include "ITimerSource.h" #include diff --git a/APLTestTools/MockPhysicalLayerAsync.cpp b/APLTestTools/MockPhysicalLayerAsync.cpp index 73f3df5a..4c071339 100644 --- a/APLTestTools/MockPhysicalLayerAsync.cpp +++ b/APLTestTools/MockPhysicalLayerAsync.cpp @@ -19,7 +19,7 @@ #include "MockPhysicalLayerAsync.h" #include "BufferHelpers.h" -#include +#include #include #include diff --git a/APLTestTools/MockTimerSource.h b/APLTestTools/MockTimerSource.h index e04b31cf..4a8a65ad 100644 --- a/APLTestTools/MockTimerSource.h +++ b/APLTestTools/MockTimerSource.h @@ -20,7 +20,7 @@ #define __MOCK_TIMER_SOURCE_H_ -#include +#include #include #include diff --git a/DNP3/AppLayer.cpp b/DNP3/AppLayer.cpp index 41ba8e4b..c4477af2 100644 --- a/DNP3/AppLayer.cpp +++ b/DNP3/AppLayer.cpp @@ -21,7 +21,7 @@ #include -#include +#include using namespace std; diff --git a/DNP3/AppLayerChannel.cpp b/DNP3/AppLayerChannel.cpp index 90c5bfb9..46da3f2d 100644 --- a/DNP3/AppLayerChannel.cpp +++ b/DNP3/AppLayerChannel.cpp @@ -19,7 +19,7 @@ #include "AppLayerChannel.h" #include -#include +#include #include "AppLayer.h" #include "AppChannelStates.h" diff --git a/DNP3/AsyncStackManager.cpp b/DNP3/AsyncStackManager.cpp index b751ccde..c92f49e3 100644 --- a/DNP3/AsyncStackManager.cpp +++ b/DNP3/AsyncStackManager.cpp @@ -173,7 +173,7 @@ void AsyncStackManager::StopVtoRouter(const std::string& arStackName, boost::uin { this->ThrowIfAlreadyShutdown(); IVtoWriter* pWriter = this->GetVtoWriter(arStackName); - VtoRouterManager::RouterRecord rec = mVtoManager.GetRouterOnWriter(pWriter, aVtoChannelId); + RouterRecord rec = mVtoManager.GetRouterOnWriter(pWriter, aVtoChannelId); this->RemoveVtoChannel(arStackName, rec.mpRouter.get()); mVtoManager.StopRouter(pWriter, aVtoChannelId); } @@ -208,10 +208,9 @@ void AsyncStackManager::RemovePort(const std::string& arPortName) pChannel->WaitUntilShutdown(); vector stacks = pChannel->StacksOnChannel(); - BOOST_FOREACH(string s, stacks) { - delete this->SeverStackFromChannel(s); - } - + BOOST_FOREACH(string s, stacks) { + this->RemoveStack(s); + } this->mScheduler.ReleaseGroup(pChannel->GetGroup()); // remove the physical layer from the list @@ -220,8 +219,10 @@ void AsyncStackManager::RemovePort(const std::string& arPortName) void AsyncStackManager::RemoveStack(const std::string& arStackName) { - this->ThrowIfAlreadyShutdown(); - delete this->SeverStackFromChannel(arStackName); + this->ThrowIfAlreadyShutdown(); + std::auto_ptr pStack(this->SeverStackFromChannel(arStackName)); + this->OnPreStackDeletion(pStack.get()); + //mTimerSrc.DeleteViaPost(pStack); } AsyncStackManager::StackRecord AsyncStackManager::GetStackRecordByName(const std::string& arStackName) @@ -311,6 +312,15 @@ void AsyncStackManager::Run() mService.Get()->reset(); } +void AsyncStackManager::OnPreStackDeletion(Stack* apStack) +{ + RouterRecordVector recs = this->mVtoManager.GetAllRoutersOnWriter(apStack->GetVtoWriter()); + + for(RouterRecordVector::iterator i = recs.begin(); i != recs.end(); ++i) { + this->mVtoManager.StopRouter(apStack->GetVtoWriter(), i->mVtoChannelId); + } +} + Stack* AsyncStackManager::SeverStackFromChannel(const std::string& arStackName) { StackMap::iterator i = mStackMap.find(arStackName); @@ -322,7 +332,7 @@ Stack* AsyncStackManager::SeverStackFromChannel(const std::string& arStackName) LOG_BLOCK(LEV_DEBUG, "Begin severing stack: " << arStackName); { Transaction tr(&mSuspendTimerSource); //need to pause execution so that this action is safe - rec.channel->RemoveStackFromChannel(arStackName); + rec.channel->RemoveStackFromChannel(arStackName); } LOG_BLOCK(LEV_DEBUG, "Done severing stack: " << arStackName); diff --git a/DNP3/AsyncStackManager.h b/DNP3/AsyncStackManager.h index 0a2b9112..0a5c92be 100644 --- a/DNP3/AsyncStackManager.h +++ b/DNP3/AsyncStackManager.h @@ -261,6 +261,17 @@ class AsyncStackManager : private Threadable, private Loggable private: + // Implement IThreadable + void Run(); + + void OnPreStackDeletion(Stack* apStack); + + // Remove and close a stack, but delegate responsibility for deletion + Stack* SeverStackFromChannel(const std::string& arStackName); + + // Add a stack from to a specified channel + void AddStackToChannel(const std::string& arStackName, Stack* apStack, LinkChannel* apChannel, const LinkRoute& arRoute); + IOService mService; TimerSourceASIO mTimerSrc; SuspendTimerSource mSuspendTimerSource; @@ -299,17 +310,8 @@ class AsyncStackManager : private Threadable, private Loggable StackRecord GetStackRecordByName(const std::string& arName); - void Run(); - - // Remove and close a stack, but delegate responsibility for deletion - Stack* SeverStackFromChannel(const std::string& arStackName); - - // Add a stack from to a specified channel - void AddStackToChannel(const std::string& arStackName, Stack* apStack, LinkChannel* apChannel, const LinkRoute& arRoute); - - size_t NumStacks() { - return mStackMap.size(); - } + + }; diff --git a/DNP3/LinkLayer.h b/DNP3/LinkLayer.h index 135d5423..910c25c9 100644 --- a/DNP3/LinkLayer.h +++ b/DNP3/LinkLayer.h @@ -22,7 +22,7 @@ #include #include -#include +#include #include "ILinkContext.h" #include "LinkFrame.h" diff --git a/DNP3/Master.cpp b/DNP3/Master.cpp index 647fb7ff..b0b105bf 100644 --- a/DNP3/Master.cpp +++ b/DNP3/Master.cpp @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include diff --git a/DNP3/VtoRouterManager.cpp b/DNP3/VtoRouterManager.cpp index d8f4b2d3..5481373e 100644 --- a/DNP3/VtoRouterManager.cpp +++ b/DNP3/VtoRouterManager.cpp @@ -36,7 +36,7 @@ namespace apl namespace dnp { -VtoRouterManager::RouterRecord::RouterRecord(const std::string& arPortName, boost::shared_ptr apRouter, IVtoWriter* apWriter, boost::uint8_t aVtoChannelId) : +RouterRecord::RouterRecord(const std::string& arPortName, boost::shared_ptr apRouter, IVtoWriter* apWriter, boost::uint8_t aVtoChannelId) : mPortName(arPortName), mpRouter(apRouter), mpWriter(apWriter), @@ -83,21 +83,22 @@ VtoRouter* VtoRouterManager::StartRouter( return pRouter.get(); } -std::vector VtoRouterManager::GetAllRouters() +std::vector VtoRouterManager::GetAllRouters() { - std::vector ret; + std::vector ret; for(size_t i = 0; i < mRecords.size(); ++i) ret.push_back(mRecords[i]); return ret; } void VtoRouterManager::StopRouter(IVtoWriter* apWriter, boost::uint8_t aVtoChannelId) { - this->StopRouter(this->GetRouterOnWriter(apWriter, aVtoChannelId).mpRouter.get()); + VtoRouter* pRouter = this->GetRouterOnWriter(apWriter, aVtoChannelId).mpRouter.get(); + this->StopRouter(pRouter, apWriter); } -std::vector VtoRouterManager::GetAllRoutersOnWriter(IVtoWriter* apWriter) +std::vector VtoRouterManager::GetAllRoutersOnWriter(IVtoWriter* apWriter) { - std::vector< VtoRouterManager::RouterRecord > ret; + std::vector< RouterRecord > ret; for(RouterRecordVector::iterator i = this->mRecords.begin(); i != mRecords.end(); ++i) { if(i->mpWriter == apWriter) ret.push_back(*i); @@ -106,7 +107,7 @@ std::vector VtoRouterManager::GetAllRoutersOnWri return ret; } -VtoRouterManager::RouterRecord VtoRouterManager::GetRouterOnWriter(IVtoWriter* apWriter, boost::uint8_t aVtoChannelId) +RouterRecord VtoRouterManager::GetRouterOnWriter(IVtoWriter* apWriter, boost::uint8_t aVtoChannelId) { for(RouterRecordVector::iterator i = this->mRecords.begin(); i != mRecords.end(); ++i) { if(i->mpWriter == apWriter && i->mVtoChannelId == aVtoChannelId) return *i; @@ -116,7 +117,7 @@ VtoRouterManager::RouterRecord VtoRouterManager::GetRouterOnWriter(IVtoWriter* a } -VtoRouterManager::RouterRecordVector::iterator VtoRouterManager::Find(IVtoWriter* apWriter, boost::uint8_t aVtoChannelId) +RouterRecordVector::iterator VtoRouterManager::Find(IVtoWriter* apWriter, boost::uint8_t aVtoChannelId) { RouterRecordVector::iterator i = this->mRecords.begin(); @@ -127,7 +128,7 @@ VtoRouterManager::RouterRecordVector::iterator VtoRouterManager::Find(IVtoWriter return i; } -VtoRouterManager::RouterRecordVector::iterator VtoRouterManager::Find(IVtoWriter* apWriter) +RouterRecordVector::iterator VtoRouterManager::Find(IVtoWriter* apWriter) { RouterRecordVector::iterator i = this->mRecords.begin(); @@ -138,13 +139,15 @@ VtoRouterManager::RouterRecordVector::iterator VtoRouterManager::Find(IVtoWriter return i; } -void VtoRouterManager::StopRouter(VtoRouter* apRouter) +void VtoRouterManager::StopRouter(VtoRouter* apRouter, IVtoWriter* apWriter) { for(RouterRecordVector::iterator i = mRecords.begin(); i != mRecords.end(); ++i) { if(i->mpRouter.get() == apRouter) { + { Transaction tr(&mSuspendTimerSource); - i->mpRouter->Shutdown(); + apWriter->RemoveVtoCallback(apRouter); + i->mpRouter->Shutdown(); } i->mpRouter->WaitForShutdown(); // blocking, when it returns we're done for good diff --git a/DNP3/VtoRouterManager.h b/DNP3/VtoRouterManager.h index 5c05f586..01bec98d 100644 --- a/DNP3/VtoRouterManager.h +++ b/DNP3/VtoRouterManager.h @@ -51,19 +51,23 @@ struct VtoRouterSettings; class IVtoWriter; class IVtoDataHandler; -class VtoRouterManager : private Loggable +class RouterRecord { -public: - class RouterRecord - { public: RouterRecord(const std::string& arPortName, boost::shared_ptr apRouter, IVtoWriter* apWriter, boost::uint8_t aVtoChannelId); - std::string mPortName; - boost::shared_ptr mpRouter; - IVtoWriter* mpWriter; - boost::uint8_t mVtoChannelId; - }; + std::string mPortName; + boost::shared_ptr mpRouter; + IVtoWriter* mpWriter; + boost::uint8_t mVtoChannelId; +}; + +typedef std::vector RouterRecordVector; + +class VtoRouterManager : private Loggable +{ +public: + VtoRouterManager(Logger* apLogger, ITimerSource* apTimerSrc, IPhysicalLayerSource* apPhysSrc); @@ -81,9 +85,7 @@ class VtoRouterManager : private Loggable private: - void StopRouter(VtoRouter* apRouter); - - typedef std::vector RouterRecordVector; + void StopRouter(VtoRouter* apRouter, IVtoWriter* apWriter); RouterRecordVector::iterator Find(IVtoWriter* apWriter, boost::uint8_t aVtoChannelId); RouterRecordVector::iterator Find(IVtoWriter* apWriter); diff --git a/DNP3Test/TestVtoOnewayIntegration.cpp b/DNP3Test/TestVtoOnewayIntegration.cpp index cb78c41c..58a1cab0 100755 --- a/DNP3Test/TestVtoOnewayIntegration.cpp +++ b/DNP3Test/TestVtoOnewayIntegration.cpp @@ -74,7 +74,7 @@ BOOST_AUTO_TEST_SUITE(VtoOnewayIntegrationSuite) BOOST_AUTO_TEST_CASE(Reconnection) { - VtoOnewayTestStack stack(true, true, false); + VtoOnewayTestStack stack(true, false, false); // start up everything, the local side should be able to open stack.remote.Start(); diff --git a/DNP3Test/TransportStackPair.h b/DNP3Test/TransportStackPair.h index 48f221d1..39f4a261 100644 --- a/DNP3Test/TransportStackPair.h +++ b/DNP3Test/TransportStackPair.h @@ -30,7 +30,7 @@ class io_service; #include #include -#include +#include #include "TransportIntegrationStack.h" diff --git a/Makefile.am b/Makefile.am index 7f7c0c49..2ea82d5b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -254,7 +254,7 @@ nobase_pkginclude_HEADERS= \ APL/TimeBoost.h \ APL/Timeout.h \ APL/TimerASIO.h \ - APL/TimerInterfaces.h \ + APL/ITimerSource.h \ APL/TimerSourceASIO.h \ APL/TimeSource.h \ APL/TimeTypes.h \ diff --git a/Terminal/LogTerminalExtension.cpp b/Terminal/LogTerminalExtension.cpp index ad3350c1..48239866 100755 --- a/Terminal/LogTerminalExtension.cpp +++ b/Terminal/LogTerminalExtension.cpp @@ -1,7 +1,7 @@ #include "LogTerminalExtension.h" #include -#include +#include #include #include diff --git a/Terminal/TerminalInterfaces.h b/Terminal/TerminalInterfaces.h index 11bcaac9..bd5efbd8 100755 --- a/Terminal/TerminalInterfaces.h +++ b/Terminal/TerminalInterfaces.h @@ -1,4 +1,21 @@ - +// +// Licensed to Green Energy Corp (www.greenenergycorp.com) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. Green Enery Corp licenses this file +// to you 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. +// #ifndef __TERMINAL_INTERFACES_H_ #define __TERMINAL_INTERFACES_H_ @@ -10,7 +27,7 @@ #include #include -#include +#include namespace apl { From 2f5dca58aab68267b9d1eb020f01dc84b30a837d Mon Sep 17 00:00:00 2001 From: jadamcrain Date: Thu, 14 Jul 2011 16:17:54 -0400 Subject: [PATCH 5/9] Fixes for build on cygwin --- APL/ITimerSource.cpp | 2 -- APL/ITimerSource.h | 1 + APL/Random.h | 2 +- DNP3/AsyncStackManager.cpp | 17 +++-------------- DNP3/VtoRouterManager.cpp | 9 +++++++++ DNP3/VtoRouterManager.h | 1 + DNP3Test/ComparingDataObserver.h | 4 ++-- DNP3Test/IntegrationTest.h | 6 +----- DNP3Test/TestIntegration.cpp | 4 +--- .../plugins/rake.cpp.enviroment.rb | 2 +- 10 files changed, 20 insertions(+), 28 deletions(-) diff --git a/APL/ITimerSource.cpp b/APL/ITimerSource.cpp index ead91ad5..579dced5 100755 --- a/APL/ITimerSource.cpp +++ b/APL/ITimerSource.cpp @@ -18,8 +18,6 @@ // #include "ITimerSource.h" -#include - namespace apl { diff --git a/APL/ITimerSource.h b/APL/ITimerSource.h index ae3112cb..3eb091a8 100755 --- a/APL/ITimerSource.h +++ b/APL/ITimerSource.h @@ -25,6 +25,7 @@ #include "DeleteAny.h" #include +#include namespace apl { diff --git a/APL/Random.h b/APL/Random.h index 2c301e7f..ade4f341 100755 --- a/APL/Random.h +++ b/APL/Random.h @@ -61,7 +61,7 @@ class Random class RandomBool : private Random { public: - RandomBool() : Random(0,1) + RandomBool() : Random(0,1) {} bool NextBool() { return Next() ? true : false; } diff --git a/DNP3/AsyncStackManager.cpp b/DNP3/AsyncStackManager.cpp index c92f49e3..8fb970b1 100644 --- a/DNP3/AsyncStackManager.cpp +++ b/DNP3/AsyncStackManager.cpp @@ -171,7 +171,7 @@ void AsyncStackManager::StartVtoRouter(const std::string& arPortName, void AsyncStackManager::StopVtoRouter(const std::string& arStackName, boost::uint8_t aVtoChannelId) { - this->ThrowIfAlreadyShutdown(); + this->ThrowIfAlreadyShutdown(); IVtoWriter* pWriter = this->GetVtoWriter(arStackName); RouterRecord rec = mVtoManager.GetRouterOnWriter(pWriter, aVtoChannelId); this->RemoveVtoChannel(arStackName, rec.mpRouter.get()); @@ -182,8 +182,7 @@ void AsyncStackManager::StopAllRoutersOnStack(const std::string& arStackName) { this->ThrowIfAlreadyShutdown(); IVtoWriter* pWriter = this->GetVtoWriter(arStackName); - //mVtoManager.StopAllRoutersOnWriter(pWriter); - //TODO - figure out why this is commented out + this->mVtoManager.StopAllRoutersOnWriter(pWriter); } IVtoWriter* AsyncStackManager::GetVtoWriter(const std::string& arStackName) @@ -221,8 +220,7 @@ void AsyncStackManager::RemoveStack(const std::string& arStackName) { this->ThrowIfAlreadyShutdown(); std::auto_ptr pStack(this->SeverStackFromChannel(arStackName)); - this->OnPreStackDeletion(pStack.get()); - //mTimerSrc.DeleteViaPost(pStack); + mVtoManager.StopAllRoutersOnWriter(pStack->GetVtoWriter()); } AsyncStackManager::StackRecord AsyncStackManager::GetStackRecordByName(const std::string& arStackName) @@ -312,15 +310,6 @@ void AsyncStackManager::Run() mService.Get()->reset(); } -void AsyncStackManager::OnPreStackDeletion(Stack* apStack) -{ - RouterRecordVector recs = this->mVtoManager.GetAllRoutersOnWriter(apStack->GetVtoWriter()); - - for(RouterRecordVector::iterator i = recs.begin(); i != recs.end(); ++i) { - this->mVtoManager.StopRouter(apStack->GetVtoWriter(), i->mVtoChannelId); - } -} - Stack* AsyncStackManager::SeverStackFromChannel(const std::string& arStackName) { StackMap::iterator i = mStackMap.find(arStackName); diff --git a/DNP3/VtoRouterManager.cpp b/DNP3/VtoRouterManager.cpp index 5481373e..78152e70 100644 --- a/DNP3/VtoRouterManager.cpp +++ b/DNP3/VtoRouterManager.cpp @@ -96,6 +96,15 @@ void VtoRouterManager::StopRouter(IVtoWriter* apWriter, boost::uint8_t aVtoChann this->StopRouter(pRouter, apWriter); } +void VtoRouterManager::StopAllRoutersOnWriter(IVtoWriter* apWriter) +{ + RouterRecordVector recs = this->GetAllRoutersOnWriter(apWriter); + + for(RouterRecordVector::iterator i = recs.begin(); i != recs.end(); ++i) { + this->StopRouter(i->mpRouter.get(), apWriter); + } +} + std::vector VtoRouterManager::GetAllRoutersOnWriter(IVtoWriter* apWriter) { std::vector< RouterRecord > ret; diff --git a/DNP3/VtoRouterManager.h b/DNP3/VtoRouterManager.h index 01bec98d..f43df712 100644 --- a/DNP3/VtoRouterManager.h +++ b/DNP3/VtoRouterManager.h @@ -78,6 +78,7 @@ class VtoRouterManager : private Loggable IVtoWriter* apWriter); void StopRouter(IVtoWriter* apWriter, boost::uint8_t aVtoChannelId); + void StopAllRoutersOnWriter(IVtoWriter* apWriter); RouterRecord GetRouterOnWriter(IVtoWriter* apWriter, boost::uint8_t aVtoChannelId); std::vector GetAllRoutersOnWriter(IVtoWriter* apWriter); diff --git a/DNP3Test/ComparingDataObserver.h b/DNP3Test/ComparingDataObserver.h index 9d3d9356..7bb049c8 100755 --- a/DNP3Test/ComparingDataObserver.h +++ b/DNP3Test/ComparingDataObserver.h @@ -82,7 +82,7 @@ class ComparingDataObserver : public apl::IDataObserver, private Loggable template void ComparingDataObserver::DescribeAny(const typename PointMap::Type& arMap, const CompareMap& arCompareMap) { - for(PointMap::Type::const_iterator i = arMap.begin(); i != arMap.end(); ++i) { + for(typename PointMap::Type::const_iterator i = arMap.begin(); i != arMap.end(); ++i) { CompareMap::const_iterator j = arCompareMap.find(i->first); if(j == arCompareMap.end()) { LOG_BLOCK(LEV_EVENT, "Missing: " << i->first << " - " << i->second.ToString()); @@ -93,7 +93,7 @@ void ComparingDataObserver::DescribeAny(const typename PointMap::Type& arMap, template void ComparingDataObserver::UpdateAny(const T& arPoint, size_t aIndex, const typename PointMap::Type& arMap, CompareMap& arCompareMap) { - PointMap::Type::const_iterator i = arMap.find(aIndex); + typename PointMap::Type::const_iterator i = arMap.find(aIndex); if(i == arMap.end()) { LOG_BLOCK(LEV_ERROR, "Unexpected index: " << aIndex << " - " << arPoint.ToString()); } diff --git a/DNP3Test/IntegrationTest.h b/DNP3Test/IntegrationTest.h index 2332f56c..fbeac151 100644 --- a/DNP3Test/IntegrationTest.h +++ b/DNP3Test/IntegrationTest.h @@ -47,11 +47,7 @@ class IntegrationTest : private Loggable public: IntegrationTest(Logger* apLogger, FilterLevel aLevel, boost::uint16_t aStartPort, size_t aNumPairs, size_t aNumPoints); - - IDataObserver* GetFanout() { - return &mFanout; - } - + void IncrementData(); bool WaitForSameData(millis_t aTimeout, bool aDescribeAnyMissingData); diff --git a/DNP3Test/TestIntegration.cpp b/DNP3Test/TestIntegration.cpp index 5c81b30b..faee7fc6 100644 --- a/DNP3Test/TestIntegration.cpp +++ b/DNP3Test/TestIntegration.cpp @@ -65,9 +65,7 @@ BOOST_AUTO_TEST_CASE(MasterToSlaveThroughput) //log.AddLogSubscriber(LogToStdio::Inst()); IntegrationTest t(log.GetLogger(FILTER_LEVEL, "test"), FILTER_LEVEL, START_PORT, - NUM_PAIRS, NUM_POINTS); - - IDataObserver* pObs = t.GetFanout(); + NUM_PAIRS, NUM_POINTS); StopWatch sw; for (size_t j = 0; j < NUM_CHANGES; ++j) { diff --git a/tools/rake_build_system/plugins/rake.cpp.enviroment.rb b/tools/rake_build_system/plugins/rake.cpp.enviroment.rb index 03aa176c..e87f10a7 100755 --- a/tools/rake_build_system/plugins/rake.cpp.enviroment.rb +++ b/tools/rake_build_system/plugins/rake.cpp.enviroment.rb @@ -83,7 +83,7 @@ def get_coverage_cc_flags end #By default, the build is set to debug -$WARN_FLAGS = ['-Wall']#, '-Wno-strict-aliasing'] +$WARN_FLAGS = ['-Wall', '-Wno-strict-aliasing'] $RELEASE_TYPE = ENV['debug'] ? 'debug' : (ENV['coverage'] ? 'coverage' : 'release') $CC_FLAGS = case $RELEASE_TYPE when 'release' From 9c0289aacfc779a01b362feff843954810fd70c4 Mon Sep 17 00:00:00 2001 From: jadamcrain Date: Fri, 15 Jul 2011 10:45:07 -0400 Subject: [PATCH 6/9] minor test tweaks and formatting --- APL/AsyncTaskBase.cpp | 2 +- APL/AsyncTaskGroup.cpp | 16 +++++++------- APL/DataTypes.h | 2 +- APL/ITimerSource.cpp | 2 +- APL/ITimerSource.h | 4 ++-- APL/PhysicalLayerMonitor.cpp | 13 ++++++------ APL/PhysicalLayerMonitor.h | 2 +- APL/PhysicalLayerMonitorStates.cpp | 14 ++++++------- APL/PhysicalLayerMonitorStates.h | 10 ++++----- APL/Random.h | 10 +++++---- APLTestTools/FanoutDataObserver.h | 6 +++--- DNP3/AsyncStackManager.cpp | 26 +++++++++++------------ DNP3/AsyncStackManager.h | 28 ++++++++++++------------- DNP3/LinkChannel.h | 2 +- DNP3/LinkLayerRouter.cpp | 6 +++--- DNP3/VtoRouterManager.cpp | 8 +++---- DNP3/VtoRouterManager.h | 6 +++--- DNP3Test/ComparingDataObserver.cpp | 26 +++++++++++------------ DNP3Test/ComparingDataObserver.h | 4 ++-- DNP3Test/IntegrationTest.cpp | 30 +++++++++++++++------------ DNP3Test/IntegrationTest.h | 14 ++++++------- DNP3Test/TestIntegration.cpp | 19 +++++++++-------- DNP3Test/TestVtoOnewayIntegration.cpp | 4 ++-- SlaveDemo/SlaveDemo.cpp | 2 +- TestAPL/TestAsyncTask.cpp | 4 ++-- TestAPL/TestPhysicalLayerMonitor.cpp | 4 ++-- 26 files changed, 135 insertions(+), 129 deletions(-) diff --git a/APL/AsyncTaskBase.cpp b/APL/AsyncTaskBase.cpp index df63fdf6..9cbe5b70 100644 --- a/APL/AsyncTaskBase.cpp +++ b/APL/AsyncTaskBase.cpp @@ -170,7 +170,7 @@ bool AsyncTaskBase::LessThanGroupLevelNoString(const AsyncTaskBase* l, const Asy } bool AsyncTaskBase::LessThanGroupLevel(const AsyncTaskBase* l, const AsyncTaskBase* r) -{ +{ return LessThanGroupLevelNoString(l, r); } diff --git a/APL/AsyncTaskGroup.cpp b/APL/AsyncTaskGroup.cpp index 0a313f58..3c868610 100644 --- a/APL/AsyncTaskGroup.cpp +++ b/APL/AsyncTaskGroup.cpp @@ -49,9 +49,9 @@ AsyncTaskGroup::~AsyncTaskGroup() { this->Shutdown(); - BOOST_FOREACH(AsyncTaskBase* p, mTaskVec) { + BOOST_FOREACH(AsyncTaskBase * p, mTaskVec) { delete p; - } + } } AsyncTaskBase* AsyncTaskGroup::Add(millis_t aPeriod, millis_t aRetryDelay, int aPriority, const TaskHandler& arCallback, const std::string& arName) @@ -68,7 +68,7 @@ AsyncTaskBase* AsyncTaskGroup::Add(millis_t aPeriod, millis_t aRetryDelay, int a void AsyncTaskGroup::ResetTasks(int aMask) { - BOOST_FOREACH(AsyncTaskBase* p, mTaskVec) { + BOOST_FOREACH(AsyncTaskBase * p, mTaskVec) { if(!p->IsRunning() && (p->GetFlags() & aMask)) p->Reset(); } } @@ -104,7 +104,7 @@ void AsyncTaskGroup::Shutdown() void AsyncTaskGroup::Enable() { - BOOST_FOREACH(AsyncTaskBase* p, mTaskVec) { + BOOST_FOREACH(AsyncTaskBase * p, mTaskVec) { p->SilentEnable(); } this->CheckState(); @@ -112,7 +112,7 @@ void AsyncTaskGroup::Enable() void AsyncTaskGroup::Disable() { - BOOST_FOREACH(AsyncTaskBase* p, mTaskVec) { + BOOST_FOREACH(AsyncTaskBase * p, mTaskVec) { p->SilentDisable(); } this->CheckState(); @@ -120,7 +120,7 @@ void AsyncTaskGroup::Disable() void AsyncTaskGroup::Enable(int aMask) { - BOOST_FOREACH(AsyncTaskBase* p, mTaskVec) { + BOOST_FOREACH(AsyncTaskBase * p, mTaskVec) { if((p->GetFlags() & aMask) != 0) p->SilentEnable(); } this->CheckState(); @@ -128,7 +128,7 @@ void AsyncTaskGroup::Enable(int aMask) void AsyncTaskGroup::Disable(int aMask) { - BOOST_FOREACH(AsyncTaskBase* p, mTaskVec) { + BOOST_FOREACH(AsyncTaskBase * p, mTaskVec) { if((p->GetFlags() & aMask) != 0) p->SilentDisable(); } this->CheckState(); @@ -181,7 +181,7 @@ boost::posix_time::ptime AsyncTaskGroup::GetUTC() const void AsyncTaskGroup::Update(const boost::posix_time::ptime& arTime) { - BOOST_FOREACH(AsyncTaskBase* p, mTaskVec) { + BOOST_FOREACH(AsyncTaskBase * p, mTaskVec) { p->UpdateTime(arTime); } } diff --git a/APL/DataTypes.h b/APL/DataTypes.h index 6b340e24..423528e7 100644 --- a/APL/DataTypes.h +++ b/APL/DataTypes.h @@ -34,7 +34,7 @@ class Binary : public BoolDataPoint public: Binary(bool aValue, boost::uint8_t aQuality = BQ_RESTART) : BoolDataPoint(BQ_RESTART, DT_BINARY, BQ_STATE) { SetQuality(aQuality); - SetValue(aValue); + SetValue(aValue); } Binary() : BoolDataPoint(BQ_RESTART, DT_BINARY, BQ_STATE) {} diff --git a/APL/ITimerSource.cpp b/APL/ITimerSource.cpp index 579dced5..38c9f031 100755 --- a/APL/ITimerSource.cpp +++ b/APL/ITimerSource.cpp @@ -21,7 +21,7 @@ namespace apl { -ITimer* ITimerSource::StartInfinite() +ITimer* ITimerSource::StartInfinite() { boost::posix_time::ptime t(boost::date_time::max_date_time); return this->Start(t, boost::bind(&ITimerSource::NullActionForInfiniteTimer)); diff --git a/APL/ITimerSource.h b/APL/ITimerSource.h index 3eb091a8..503a4bd4 100755 --- a/APL/ITimerSource.h +++ b/APL/ITimerSource.h @@ -49,7 +49,7 @@ typedef boost::function ExpirationHandler; class ITimerSource { public: - virtual ~ITimerSource() {} + virtual ~ITimerSource() {} ITimer* StartInfinite(); @@ -65,7 +65,7 @@ class ITimerSource /** Delete any type via a Post */ template void DeleteViaPost(T* apType); - + private: static void NullActionForInfiniteTimer(); diff --git a/APL/PhysicalLayerMonitor.cpp b/APL/PhysicalLayerMonitor.cpp index 6498ca38..e935eee3 100755 --- a/APL/PhysicalLayerMonitor.cpp +++ b/APL/PhysicalLayerMonitor.cpp @@ -63,17 +63,16 @@ void PhysicalLayerMonitor::AddObserver(IPhysicalLayerObserver* apObserver) bool PhysicalLayerMonitor::WaitForShutdown(millis_t aTimeoutMs) { - CriticalSection cs(&mLock); + CriticalSection cs(&mLock); - while(!mFinalShutdown) - { + while(!mFinalShutdown) { if(aTimeoutMs < 0) cs.Wait(); else { cs.TimedWait(aTimeoutMs); break; } } - + return mFinalShutdown; } @@ -82,7 +81,7 @@ void PhysicalLayerMonitor::ChangeState(IMonitorState* apState) LOG_BLOCK(LEV_DEBUG, mpState->ConvertToString() << " -> " << apState->ConvertToString() << " : " << mpPhys->ConvertStateToString()); IMonitorState* pLast = mpState; - CriticalSection cs(&mLock); + CriticalSection cs(&mLock); mpState = apState; if(pLast->GetState() != apState->GetState()) { for(ObserverSet::iterator i = mObservers.begin(); i != mObservers.end(); ++i) (*i)->OnStateChange(apState->GetState()); @@ -144,7 +143,7 @@ void PhysicalLayerMonitor::OnOpenTimerExpiration() void PhysicalLayerMonitor::_OnOpenFailure() { - LOG_BLOCK(LEV_DEBUG, "_OnOpenFailure()"); + LOG_BLOCK(LEV_DEBUG, "_OnOpenFailure()"); mpState->OnOpenFailure(this); this->OnPhysicalLayerOpenFailureCallback(); } @@ -158,7 +157,7 @@ void PhysicalLayerMonitor::_OnLowerLayerUp() void PhysicalLayerMonitor::_OnLowerLayerDown() { - LOG_BLOCK(LEV_DEBUG, "_OnLowerLayerDown"); + LOG_BLOCK(LEV_DEBUG, "_OnLowerLayerDown"); mpState->OnLayerClose(this); this->OnPhysicalLayerCloseCallback(); } diff --git a/APL/PhysicalLayerMonitor.h b/APL/PhysicalLayerMonitor.h index da69e83b..500f70cd 100755 --- a/APL/PhysicalLayerMonitor.h +++ b/APL/PhysicalLayerMonitor.h @@ -103,7 +103,7 @@ class PhysicalLayerMonitor : public IHandlerAsync void OnOpenTimerExpiration(); /// Cancels the open timer - void CancelOpenTimer(); + void CancelOpenTimer(); /* --- Internal helper functions --- */ diff --git a/APL/PhysicalLayerMonitorStates.cpp b/APL/PhysicalLayerMonitorStates.cpp index 03b54bd1..c58f629b 100755 --- a/APL/PhysicalLayerMonitorStates.cpp +++ b/APL/PhysicalLayerMonitorStates.cpp @@ -186,7 +186,7 @@ void MonitorStateSuspendedBase::OnStartOneRequest(PhysicalLayerMonitor* apContex } void MonitorStateSuspendedBase::OnShutdownRequest(PhysicalLayerMonitor* apContext) -{ +{ MonitorStateActions::ChangeState(apContext, MonitorStateShutdown::Inst()); } @@ -297,19 +297,19 @@ void MonitorStateOpen::OnStartOneRequest(PhysicalLayerMonitor* apContext) void MonitorStateOpen::OnCloseRequest(PhysicalLayerMonitor* apContext) { - MonitorStateActions::ChangeState(apContext, MonitorStateClosing::Inst()); + MonitorStateActions::ChangeState(apContext, MonitorStateClosing::Inst()); MonitorStateActions::AsyncClose(apContext); } void MonitorStateOpen::OnSuspendRequest(PhysicalLayerMonitor* apContext) { - MonitorStateActions::ChangeState(apContext, MonitorStateSuspending::Inst()); + MonitorStateActions::ChangeState(apContext, MonitorStateSuspending::Inst()); MonitorStateActions::AsyncClose(apContext); } void MonitorStateOpen::OnShutdownRequest(PhysicalLayerMonitor* apContext) { - MonitorStateActions::ChangeState(apContext, MonitorStateShutingDown::Inst()); + MonitorStateActions::ChangeState(apContext, MonitorStateShutingDown::Inst()); MonitorStateActions::AsyncClose(apContext); } @@ -399,17 +399,17 @@ void MonitorStateClosing::OnSuspendRequest(PhysicalLayerMonitor* apContext) MonitorStateSuspending MonitorStateSuspending::mInstance; void MonitorStateSuspending::OnLayerClose(PhysicalLayerMonitor* apContext) -{ +{ MonitorStateActions::ChangeState(apContext, MonitorStateSuspended::Inst()); } void MonitorStateSuspending::OnStartRequest(PhysicalLayerMonitor* apContext) -{ +{ MonitorStateActions::ChangeState(apContext, MonitorStateClosing::Inst()); } void MonitorStateSuspending::OnShutdownRequest(PhysicalLayerMonitor* apContext) -{ +{ MonitorStateActions::ChangeState(apContext, MonitorStateShutingDown::Inst()); } diff --git a/APL/PhysicalLayerMonitorStates.h b/APL/PhysicalLayerMonitorStates.h index a0a8fae5..bd884d57 100755 --- a/APL/PhysicalLayerMonitorStates.h +++ b/APL/PhysicalLayerMonitorStates.h @@ -177,21 +177,21 @@ class MonitorStateSuspendedBase : public virtual IMonitorState, private NotWaitingForTimer, private IgnoresClose, private IgnoresSuspend -{ +{ void OnStartRequest(PhysicalLayerMonitor* apContext); void OnStartOneRequest(PhysicalLayerMonitor* apContext); void OnShutdownRequest(PhysicalLayerMonitor* apContext); }; -class MonitorStateSuspended : public MonitorStateSuspendedBase +class MonitorStateSuspended : public MonitorStateSuspendedBase { - MACRO_MONITOR_SINGLETON(MonitorStateSuspended, PLS_CLOSED, false); + MACRO_MONITOR_SINGLETON(MonitorStateSuspended, PLS_CLOSED, false); }; -class MonitorStateInit : public MonitorStateSuspendedBase +class MonitorStateInit : public MonitorStateSuspendedBase { - MACRO_MONITOR_SINGLETON(MonitorStateInit, PLS_CLOSED, false); + MACRO_MONITOR_SINGLETON(MonitorStateInit, PLS_CLOSED, false); }; class MonitorStateOpeningBase : public virtual IMonitorState, diff --git a/APL/Random.h b/APL/Random.h index ade4f341..6e17ea31 100755 --- a/APL/Random.h +++ b/APL/Random.h @@ -60,11 +60,13 @@ class Random class RandomBool : private Random { - public: - RandomBool() : Random(0,1) - {} +public: + RandomBool() : Random(0, 1) + {} - bool NextBool() { return Next() ? true : false; } + bool NextBool() { + return Next() ? true : false; + } }; diff --git a/APLTestTools/FanoutDataObserver.h b/APLTestTools/FanoutDataObserver.h index 51661636..88dbcec3 100755 --- a/APLTestTools/FanoutDataObserver.h +++ b/APLTestTools/FanoutDataObserver.h @@ -30,7 +30,7 @@ class FanoutDataObserver : public IDataObserver { public: - void AddObserver(IDataObserver* apObserver) { + void AddObserver(IDataObserver* apObserver) { mObservers.push_back(apObserver); } @@ -40,9 +40,9 @@ class FanoutDataObserver : public IDataObserver void _End() { mBuffer.End(); - BOOST_FOREACH(IDataObserver* p, mObservers) { + BOOST_FOREACH(IDataObserver * p, mObservers) { mBuffer.FlushUpdates(p, false); - } + } } void _Update(const Binary& arPoint, size_t aIndex) { diff --git a/DNP3/AsyncStackManager.cpp b/DNP3/AsyncStackManager.cpp index 8fb970b1..5134f314 100644 --- a/DNP3/AsyncStackManager.cpp +++ b/DNP3/AsyncStackManager.cpp @@ -182,7 +182,7 @@ void AsyncStackManager::StopAllRoutersOnStack(const std::string& arStackName) { this->ThrowIfAlreadyShutdown(); IVtoWriter* pWriter = this->GetVtoWriter(arStackName); - this->mVtoManager.StopAllRoutersOnWriter(pWriter); + this->mVtoManager.StopAllRoutersOnWriter(pWriter); } IVtoWriter* AsyncStackManager::GetVtoWriter(const std::string& arStackName) @@ -195,21 +195,21 @@ IVtoWriter* AsyncStackManager::GetVtoWriter(const std::string& arStackName) void AsyncStackManager::RemovePort(const std::string& arPortName) { this->ThrowIfAlreadyShutdown(); - std::auto_ptr pChannel(this->GetChannelOrExcept(arPortName)); //will delete at end of function + std::auto_ptr pChannel(this->GetChannelOrExcept(arPortName)); //will delete at end of function mChannelNameToChannel.erase(arPortName); { // Tell the channel to shut down permanently Transaction tr(&mSuspendTimerSource); pChannel->GetGroup()->Shutdown(); // no more task callbacks - pChannel->BeginShutdown(); + pChannel->BeginShutdown(); } - pChannel->WaitUntilShutdown(); - + pChannel->WaitUntilShutdown(); + vector stacks = pChannel->StacksOnChannel(); - BOOST_FOREACH(string s, stacks) { - this->RemoveStack(s); - } + BOOST_FOREACH(string s, stacks) { + this->RemoveStack(s); + } this->mScheduler.ReleaseGroup(pChannel->GetGroup()); // remove the physical layer from the list @@ -226,7 +226,7 @@ void AsyncStackManager::RemoveStack(const std::string& arStackName) AsyncStackManager::StackRecord AsyncStackManager::GetStackRecordByName(const std::string& arStackName) { StackMap::iterator i = mStackMap.find(arStackName); - if (i == mStackMap.end()) throw ArgumentException(LOCATION, "Unknown stack"); + if (i == mStackMap.end()) throw ArgumentException(LOCATION, "Unknown stack"); return i->second; } @@ -311,17 +311,17 @@ void AsyncStackManager::Run() } Stack* AsyncStackManager::SeverStackFromChannel(const std::string& arStackName) -{ +{ StackMap::iterator i = mStackMap.find(arStackName); if(i == mStackMap.end()) throw ArgumentException(LOCATION, "Stack not found: " + arStackName); StackRecord rec = i->second; mStackMap.erase(i); - - LOG_BLOCK(LEV_DEBUG, "Begin severing stack: " << arStackName); + + LOG_BLOCK(LEV_DEBUG, "Begin severing stack: " << arStackName); { Transaction tr(&mSuspendTimerSource); //need to pause execution so that this action is safe - rec.channel->RemoveStackFromChannel(arStackName); + rec.channel->RemoveStackFromChannel(arStackName); } LOG_BLOCK(LEV_DEBUG, "Done severing stack: " << arStackName); diff --git a/DNP3/AsyncStackManager.h b/DNP3/AsyncStackManager.h index 0a5c92be..4fc62368 100644 --- a/DNP3/AsyncStackManager.h +++ b/DNP3/AsyncStackManager.h @@ -264,7 +264,7 @@ class AsyncStackManager : private Threadable, private Loggable // Implement IThreadable void Run(); - void OnPreStackDeletion(Stack* apStack); + void OnPreStackDeletion(Stack* apStack); // Remove and close a stack, but delegate responsibility for deletion Stack* SeverStackFromChannel(const std::string& arStackName); @@ -285,33 +285,33 @@ class AsyncStackManager : private Threadable, private Loggable void ThrowIfAlreadyShutdown(); struct StackRecord { - StackRecord() : - stack(NULL), channel(NULL) - {} + StackRecord() : + stack(NULL), channel(NULL) + {} - StackRecord(Stack* apStack, LinkChannel* apChannel) : - stack(apStack), channel(apChannel) - {} + StackRecord(Stack* apStack, LinkChannel* apChannel) : + stack(apStack), channel(apChannel) + {} - Stack* stack; - LinkChannel* channel; + Stack* stack; + LinkChannel* channel; }; typedef std::map StackMap; // maps a stack name the stack and it's channel StackMap mStackMap; - - typedef std::map ChannelToChannelMap; + + typedef std::map ChannelToChannelMap; ChannelToChannelMap mChannelNameToChannel; // maps a channel name to a channel instance LinkChannel* GetOrCreateChannel(const std::string& arName); LinkChannel* GetChannelOrExcept(const std::string& arName); LinkChannel* GetChannelMaybeNull(const std::string& arName); LinkChannel* CreateChannel(const std::string& arName); - + StackRecord GetStackRecordByName(const std::string& arName); - - + + }; diff --git a/DNP3/LinkChannel.h b/DNP3/LinkChannel.h index adff0bb6..7642fcc7 100755 --- a/DNP3/LinkChannel.h +++ b/DNP3/LinkChannel.h @@ -55,7 +55,7 @@ class LinkChannel : private LinkLayerRouter public: - LinkChannel(Logger* apLogger, const std::string& arName, ITimerSource* apTimerSrc, IPhysicalLayerAsync* apPhys, AsyncTaskGroup* apTaskGroup, millis_t aOpenRetry); + LinkChannel(Logger* apLogger, const std::string& arName, ITimerSource* apTimerSrc, IPhysicalLayerAsync* apPhys, AsyncTaskGroup* apTaskGroup, millis_t aOpenRetry); void BindStackToChannel(const std::string& arStackName, Stack* apStack, const LinkRoute& arRoute); void RemoveStackFromChannel(const std::string& arStackName); diff --git a/DNP3/LinkLayerRouter.cpp b/DNP3/LinkLayerRouter.cpp index 7a1f7597..65a20f7b 100644 --- a/DNP3/LinkLayerRouter.cpp +++ b/DNP3/LinkLayerRouter.cpp @@ -71,19 +71,19 @@ void LinkLayerRouter::RemoveContext(const LinkRoute& arRoute) AddressMap::iterator i = mAddressMap.find(arRoute); if(i == mAddressMap.end()) throw ArgumentException(LOCATION, "LinkRoute not bound: " + arRoute.ToString()); else { - + ILinkContext* pContext = i->second; mAddressMap.erase(i); if(this->GetState() == PLS_OPEN) pContext->OnLowerLayerDown(); - + // if no stacks are bound, suspend the router if(mAddressMap.size() == 0) { this->Suspend(); } } - + } ILinkContext* LinkLayerRouter::GetContext(const LinkRoute& arRoute) diff --git a/DNP3/VtoRouterManager.cpp b/DNP3/VtoRouterManager.cpp index 78152e70..a07fb42a 100644 --- a/DNP3/VtoRouterManager.cpp +++ b/DNP3/VtoRouterManager.cpp @@ -100,9 +100,9 @@ void VtoRouterManager::StopAllRoutersOnWriter(IVtoWriter* apWriter) { RouterRecordVector recs = this->GetAllRoutersOnWriter(apWriter); - for(RouterRecordVector::iterator i = recs.begin(); i != recs.end(); ++i) { + for(RouterRecordVector::iterator i = recs.begin(); i != recs.end(); ++i) { this->StopRouter(i->mpRouter.get(), apWriter); - } + } } std::vector VtoRouterManager::GetAllRoutersOnWriter(IVtoWriter* apWriter) @@ -152,11 +152,11 @@ void VtoRouterManager::StopRouter(VtoRouter* apRouter, IVtoWriter* apWriter) { for(RouterRecordVector::iterator i = mRecords.begin(); i != mRecords.end(); ++i) { if(i->mpRouter.get() == apRouter) { - + { Transaction tr(&mSuspendTimerSource); apWriter->RemoveVtoCallback(apRouter); - i->mpRouter->Shutdown(); + i->mpRouter->Shutdown(); } i->mpRouter->WaitForShutdown(); // blocking, when it returns we're done for good diff --git a/DNP3/VtoRouterManager.h b/DNP3/VtoRouterManager.h index f43df712..bc5414c0 100644 --- a/DNP3/VtoRouterManager.h +++ b/DNP3/VtoRouterManager.h @@ -53,8 +53,8 @@ class IVtoDataHandler; class RouterRecord { - public: - RouterRecord(const std::string& arPortName, boost::shared_ptr apRouter, IVtoWriter* apWriter, boost::uint8_t aVtoChannelId); +public: + RouterRecord(const std::string& arPortName, boost::shared_ptr apRouter, IVtoWriter* apWriter, boost::uint8_t aVtoChannelId); std::string mPortName; boost::shared_ptr mpRouter; @@ -86,7 +86,7 @@ class VtoRouterManager : private Loggable private: - void StopRouter(VtoRouter* apRouter, IVtoWriter* apWriter); + void StopRouter(VtoRouter* apRouter, IVtoWriter* apWriter); RouterRecordVector::iterator Find(IVtoWriter* apWriter, boost::uint8_t aVtoChannelId); RouterRecordVector::iterator Find(IVtoWriter* apWriter); diff --git a/DNP3Test/ComparingDataObserver.cpp b/DNP3Test/ComparingDataObserver.cpp index e4100a70..f980eeda 100755 --- a/DNP3Test/ComparingDataObserver.cpp +++ b/DNP3Test/ComparingDataObserver.cpp @@ -24,12 +24,12 @@ namespace apl namespace dnp { -ComparingDataObserver::ComparingDataObserver(Logger* apLogger, FlexibleDataObserver* apObserver) : +ComparingDataObserver::ComparingDataObserver(Logger* apLogger, FlexibleDataObserver* apObserver) : Loggable(apLogger), mSameData(false), mpObserver(apObserver) { - + } void ComparingDataObserver::Reset() @@ -39,24 +39,24 @@ void ComparingDataObserver::Reset() mAnalogMap.clear(); mCounterMap.clear(); mControlStatusMap.clear(); - mSetpointStatusMap.clear(); + mSetpointStatusMap.clear(); mSameData = false; } bool ComparingDataObserver::IsSameData() -{ - size_t required = mpObserver->mBinaryMap.size() + - mpObserver->mAnalogMap.size() + - mpObserver->mCounterMap.size(); +{ + size_t required = mpObserver->mBinaryMap.size() + + mpObserver->mAnalogMap.size() + + mpObserver->mCounterMap.size(); - size_t actual = mBinaryMap.size() + - mAnalogMap.size() + - mCounterMap.size(); + size_t actual = mBinaryMap.size() + + mAnalogMap.size() + + mCounterMap.size(); LOG_BLOCK(LEV_EVENT, actual << " of " << required); return (required == actual); - + } bool ComparingDataObserver::WaitForSameData(millis_t aWaitMs) @@ -79,13 +79,13 @@ void ComparingDataObserver::_Start() } void ComparingDataObserver::_End() -{ +{ if(this->IsSameData()) { mSameData = true; mLock.Broadcast(); } mLock.Unlock(); - + } void ComparingDataObserver::_Update(const Binary& arPoint, size_t aIndex) diff --git a/DNP3Test/ComparingDataObserver.h b/DNP3Test/ComparingDataObserver.h index 7bb049c8..a0e7c3f8 100755 --- a/DNP3Test/ComparingDataObserver.h +++ b/DNP3Test/ComparingDataObserver.h @@ -50,9 +50,9 @@ class ComparingDataObserver : public apl::IDataObserver, private Loggable bool mSameData; bool IsSameData(); - + SigLock mLock; - FlexibleDataObserver* mpObserver; + FlexibleDataObserver* mpObserver; typedef std::map CompareMap; diff --git a/DNP3Test/IntegrationTest.cpp b/DNP3Test/IntegrationTest.cpp index d76d57bd..58e0fcad 100644 --- a/DNP3Test/IntegrationTest.cpp +++ b/DNP3Test/IntegrationTest.cpp @@ -42,9 +42,9 @@ using namespace std; using namespace apl; using namespace apl::dnp; -IntegrationTest::IntegrationTest(Logger* apLogger, FilterLevel aLevel, boost::uint16_t aStartPort, size_t aNumPairs, size_t aNumPoints) : +IntegrationTest::IntegrationTest(Logger* apLogger, FilterLevel aLevel, boost::uint16_t aStartPort, size_t aNumPairs, size_t aNumPoints) : Loggable(apLogger), - M_START_PORT(aStartPort), + M_START_PORT(aStartPort), mManager(apLogger), NUM_POINTS(aNumPoints) { @@ -53,7 +53,7 @@ IntegrationTest::IntegrationTest(Logger* apLogger, FilterLevel aLevel, boost::ui for (size_t i = 0; i < aNumPairs; ++i) { AddStackPair(aLevel, aNumPoints); } - mFanout.AddObserver(&mLocalFDO); + mFanout.AddObserver(&mLocalFDO); } void IntegrationTest::InitLocalObserver() @@ -63,7 +63,7 @@ void IntegrationTest::InitLocalObserver() mLocalFDO.Update(this->RandomBinary(), i); mLocalFDO.Update(this->RandomAnalog(), i); mLocalFDO.Update(this->RandomCounter(), i); - } + } } void IntegrationTest::ResetObservers() @@ -74,7 +74,7 @@ void IntegrationTest::ResetObservers() } bool IntegrationTest::WaitForSameData(millis_t aTimeout, bool aDescribeAnyMissingData) -{ +{ LOG_BLOCK(LEV_EVENT, "Wait for same data"); for (size_t i = 0; i < this->mMasterObservers.size(); ++i) { @@ -88,23 +88,27 @@ bool IntegrationTest::WaitForSameData(millis_t aTimeout, bool aDescribeAnyMissin return true; } -void IntegrationTest::IncrementData() +size_t IntegrationTest::IncrementData() { LOG_BLOCK(LEV_EVENT, "Incrementing data"); + size_t num = 0; + this->ResetObservers(); /* * Resource Acquisition Is Initialization (RAII) Pattern. * When the Transaction instance is created, it acquires the resource. * When it is destroyed, it releases the resource. The scoping using * the {} block forces destruction of the Transaction at the right time. - */ + */ Transaction tr(&mFanout); for (size_t i = 0; i < NUM_POINTS; ++i) { mFanout.Update(this->Next(mLocalFDO.mBinaryMap[i]), i); mFanout.Update(this->Next(mLocalFDO.mAnalogMap[i]), i); mFanout.Update(this->Next(mLocalFDO.mCounterMap[i]), i); - } + num += 3; + } + return num; } Binary IntegrationTest::RandomBinary() @@ -114,32 +118,32 @@ Binary IntegrationTest::RandomBinary() } Analog IntegrationTest::RandomAnalog() -{ +{ Analog v(mRandomInt32.Next(), AQ_ONLINE); return v; } Counter IntegrationTest::RandomCounter() -{ +{ Counter v(mRandomUInt32.Next(), CQ_ONLINE); return v; } Binary IntegrationTest::Next(const Binary& arPoint) { - Binary point(!arPoint.GetValue(), arPoint.GetQuality()); + Binary point(!arPoint.GetValue(), arPoint.GetQuality()); return point; } Analog IntegrationTest::Next(const Analog& arPoint) { - Analog point(arPoint.GetValue()+1, arPoint.GetQuality()); + Analog point(arPoint.GetValue() + 1, arPoint.GetQuality()); return point; } Counter IntegrationTest::Next(const Counter& arPoint) { - Counter point(arPoint.GetValue()+1, arPoint.GetQuality()); + Counter point(arPoint.GetValue() + 1, arPoint.GetQuality()); return point; } diff --git a/DNP3Test/IntegrationTest.h b/DNP3Test/IntegrationTest.h index fbeac151..3dfbc8a0 100644 --- a/DNP3Test/IntegrationTest.h +++ b/DNP3Test/IntegrationTest.h @@ -47,14 +47,14 @@ class IntegrationTest : private Loggable public: IntegrationTest(Logger* apLogger, FilterLevel aLevel, boost::uint16_t aStartPort, size_t aNumPairs, size_t aNumPoints); - - void IncrementData(); - + + size_t IncrementData(); + bool WaitForSameData(millis_t aTimeout, bool aDescribeAnyMissingData); - + AsyncStackManager* GetManager() { return &mManager; - } + } private: @@ -69,7 +69,7 @@ class IntegrationTest : private Loggable Binary Next(const Binary& arPoint); Analog Next(const Analog& arPoint); Counter Next(const Counter& arPoint); - + void RegisterChange(); void AddStackPair(FilterLevel aLevel, size_t aNumPoints); @@ -82,7 +82,7 @@ class IntegrationTest : private Loggable RandomBool mRandomBool; const boost::uint16_t M_START_PORT; - + FlexibleDataObserver mLocalFDO; MockCommandAcceptor mCmdAcceptor; diff --git a/DNP3Test/TestIntegration.cpp b/DNP3Test/TestIntegration.cpp index faee7fc6..64e67664 100644 --- a/DNP3Test/TestIntegration.cpp +++ b/DNP3Test/TestIntegration.cpp @@ -54,7 +54,7 @@ BOOST_AUTO_TEST_SUITE(IntegrationSuite) const boost::uint16_t START_PORT = MACRO_PORT_START; const size_t NUM_PAIRS = MACRO_NUM_PAIRS; const size_t NUM_POINTS = 500; -const size_t NUM_CHANGES = 10; +const size_t NUM_CHANGE_SETS = 10; const FilterLevel FILTER_LEVEL = LEV_WARNING; BOOST_AUTO_TEST_CASE(MasterToSlaveThroughput) @@ -62,20 +62,21 @@ BOOST_AUTO_TEST_CASE(MasterToSlaveThroughput) EventLog log; //LogToStdio::Inst()->SetPrintLocation(true); - //log.AddLogSubscriber(LogToStdio::Inst()); + //log.AddLogSubscriber(LogToStdio::Inst()); IntegrationTest t(log.GetLogger(FILTER_LEVEL, "test"), FILTER_LEVEL, START_PORT, - NUM_PAIRS, NUM_POINTS); + NUM_PAIRS, NUM_POINTS); + size_t num_points_per_pair = 0; StopWatch sw; - for (size_t j = 0; j < NUM_CHANGES; ++j) { - t.IncrementData(); - BOOST_REQUIRE(t.WaitForSameData(20000, true)); - } + for (size_t j = 0; j < NUM_CHANGE_SETS; ++j) { + num_points_per_pair += t.IncrementData(); + BOOST_REQUIRE(t.WaitForSameData(20000, true)); + } if (OUTPUT_PERF_NUMBERS) { double elapsed_sec = sw.Elapsed() / 1000.0; - size_t points = 3 * NUM_POINTS * NUM_CHANGES * NUM_PAIRS * 2; + size_t points = num_points_per_pair * NUM_PAIRS * 2; cout << "num points: " << points << endl; cout << "elapsed seconds: " << elapsed_sec << endl; cout << "points/sec: " << points / elapsed_sec << endl; @@ -86,7 +87,7 @@ BOOST_AUTO_TEST_CASE(MasterToSlaveThroughput) // TODO - Factor this test into smaller tests BOOST_AUTO_TEST_CASE(IntegrationTestConstructionDestruction) { - EventLog log; + EventLog log; //log.AddLogSubscriber(LogToStdio::Inst()); IntegrationTest t(log.GetLogger(LEV_WARNING, "test"), LEV_WARNING, START_PORT, diff --git a/DNP3Test/TestVtoOnewayIntegration.cpp b/DNP3Test/TestVtoOnewayIntegration.cpp index 58a1cab0..870eedee 100755 --- a/DNP3Test/TestVtoOnewayIntegration.cpp +++ b/DNP3Test/TestVtoOnewayIntegration.cpp @@ -89,7 +89,7 @@ BOOST_AUTO_TEST_CASE(Reconnection) BOOST_REQUIRE(stack.WaitForBothSides(PLS_OPEN)); // test that data is correctly sent both ways - + data.Randomize(); stack.local.ExpectData(data); stack.local.WriteData(data); @@ -99,7 +99,7 @@ BOOST_AUTO_TEST_CASE(Reconnection) // close the remote loopback server, which will cause both sides to close and reopen stack.remote.Close(); stack.Log(LOCATION, "Waiting for both sides to close"); - BOOST_REQUIRE(stack.WaitForBothSides(PLS_CLOSED)); + BOOST_REQUIRE(stack.WaitForBothSides(PLS_CLOSED)); } } diff --git a/SlaveDemo/SlaveDemo.cpp b/SlaveDemo/SlaveDemo.cpp index 57b00816..230a80c9 100755 --- a/SlaveDemo/SlaveDemo.cpp +++ b/SlaveDemo/SlaveDemo.cpp @@ -31,7 +31,7 @@ SlaveDemoBase::SlaveDemoBase(Logger* apLogger) : IOServiceThread(apLogger, this->Get()), mTimerSource(this->Get()), mpInfiniteTimer(mTimerSource.StartInfinite()) -{ +{ // Create a notifier that when called will post a call to OnCommandNotify INotifier* pNotifier = mPostSource.Get(boost::bind(&SlaveDemoBase::OnCommandNotify, this), &mTimerSource); diff --git a/TestAPL/TestAsyncTask.cpp b/TestAPL/TestAsyncTask.cpp index 9545a6f4..e36b816b 100644 --- a/TestAPL/TestAsyncTask.cpp +++ b/TestAPL/TestAsyncTask.cpp @@ -169,11 +169,11 @@ BOOST_AUTO_TEST_CASE(NonPeriodic) fakeTime.SetToNow(); AsyncTaskScheduler ats(&mts, &fakeTime); AsyncTaskGroup* pGroup = ats.CreateNewGroup(); - + AsyncTaskBase* pT1 = pGroup->Add(-1, 100, 0, mth.GetHandler()); //non-periodic task AsyncTaskBase* pT2 = pGroup->Add(2000, 100, 0, mth.GetHandler()); - + pGroup->Enable(); //complete both the tasks diff --git a/TestAPL/TestPhysicalLayerMonitor.cpp b/TestAPL/TestPhysicalLayerMonitor.cpp index 5357de94..5fe60979 100755 --- a/TestAPL/TestPhysicalLayerMonitor.cpp +++ b/TestAPL/TestPhysicalLayerMonitor.cpp @@ -276,12 +276,12 @@ BOOST_AUTO_TEST_CASE(OpenFailureGoesToClosedIfSuspended) BOOST_AUTO_TEST_CASE(ShutdownPostsToTimer) { - TestObject test; + TestObject test; BOOST_REQUIRE_EQUAL(0, test.mts.NumActive()); BOOST_REQUIRE_FALSE(test.monitor.WaitForShutdown(0)); test.monitor.Shutdown(); BOOST_REQUIRE_EQUAL(PLS_SHUTDOWN, test.monitor.GetState()); - BOOST_REQUIRE_EQUAL(1, test.mts.NumActive()); + BOOST_REQUIRE_EQUAL(1, test.mts.NumActive()); BOOST_REQUIRE_FALSE(test.monitor.WaitForShutdown(0)); BOOST_REQUIRE(test.mts.DispatchOne()); BOOST_REQUIRE(test.monitor.WaitForShutdown()); //wait indefinitely, but it's already shutdown From e34dfdfe1355dc5d0a3440a9d43650ec07b6b9c6 Mon Sep 17 00:00:00 2001 From: jadamcrain Date: Fri, 15 Jul 2011 16:44:41 -0400 Subject: [PATCH 7/9] Fixed the broken functionality in Terminal --- Terminal/Terminal.cpp | 11 ++++------- Terminal/Terminal.h | 9 +++------ TerminalTest/TestTerminal.cpp | 4 +--- TestSet/StackHelpers.cpp | 2 +- 4 files changed, 9 insertions(+), 17 deletions(-) diff --git a/Terminal/Terminal.cpp b/Terminal/Terminal.cpp index 523678b1..e19d22ac 100755 --- a/Terminal/Terminal.cpp +++ b/Terminal/Terminal.cpp @@ -29,11 +29,12 @@ Terminal::Terminal(Logger* apLogger, IPhysicalLayerAsync* apPhysical, ITimerSour mSendBuffer(1024), mpPhysical(apPhysical), mpTimerSrc(apTimerSrc), - mpInfiniteTimer(NULL), + mpInfiniteTimer(apTimerSrc->StartInfinite()), mBanner(arBanner), mIOMode(aIOMode) { this->InitCmdHandlers(); + this->Start(); } void Terminal::InitCmdHandlers() @@ -97,11 +98,6 @@ void Terminal::Post(const ExpirationHandler& arHandler) mpTimerSrc->Post(arHandler); } -void Terminal::Null() -{ - throw InvalidStateException(LOCATION, "Function should be uncallable"); -} - retcode Terminal::HandleHelp(std::vector& arTokens) { @@ -313,7 +309,8 @@ retcode Terminal::HandleDefault(std::vector&) } retcode Terminal::HandleQuit(std::vector&) -{ +{ + this->mpInfiniteTimer->Cancel(); this->Shutdown(); return SUCCESS; } diff --git a/Terminal/Terminal.h b/Terminal/Terminal.h index d7f082eb..27c2a63e 100755 --- a/Terminal/Terminal.h +++ b/Terminal/Terminal.h @@ -48,13 +48,11 @@ class Terminal : private LineReader, public ITerminal void _OnSendSuccess(); void _OnSendFailure(); + /* void Init() { this->Start(); } - - void ShutdownForever() { - this->Shutdown(); - } + */ private: @@ -75,8 +73,7 @@ class Terminal : private LineReader, public ITerminal IPhysicalLayerAsync* mpPhysical; ITimerSource* mpTimerSrc; - ITimer* mpInfiniteTimer; - void Null(); + ITimer* mpInfiniteTimer; std::string mBanner; bool mIOMode; diff --git a/TerminalTest/TestTerminal.cpp b/TerminalTest/TestTerminal.cpp index 337a9f78..dc1889cc 100755 --- a/TerminalTest/TestTerminal.cpp +++ b/TerminalTest/TestTerminal.cpp @@ -153,7 +153,7 @@ BOOST_AUTO_TEST_CASE(TerminalInteractions) LogTerminalExtension lte(&log); Terminal trm(pLoggerA, &phys, &mts, "Test Terminal", false); trm.AddExtension(<e); - trm.Init(); + //trm.Init(); BOOST_REQUIRE(mts.DispatchOne()); @@ -166,8 +166,6 @@ BOOST_AUTO_TEST_CASE(TerminalInteractions) TestSetCommands(&phys); TestRunCommands(&phys, logger); - - trm.ShutdownForever(); } BOOST_AUTO_TEST_SUITE_END() diff --git a/TestSet/StackHelpers.cpp b/TestSet/StackHelpers.cpp index b88522a2..6610eef3 100644 --- a/TestSet/StackHelpers.cpp +++ b/TestSet/StackHelpers.cpp @@ -63,7 +63,7 @@ StackBase::StackBase(const APLXML_Base::PhysicalLayerList_t& arList, FilterLevel void StackBase::Run() { - trm.Init(); + //trm.Init(); mTermThread.Run(); // blocking mTermThread.Stop(); } From 3c2b2f11b55ca1ee867b1b1ee7c9b839af993e16 Mon Sep 17 00:00:00 2001 From: jadamcrain Date: Fri, 15 Jul 2011 17:06:05 -0400 Subject: [PATCH 8/9] Updated Makefile.am --- Makefile.am | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile.am b/Makefile.am index 2ea82d5b..14c68e2a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -31,6 +31,7 @@ libopendnp3_apl_la_SOURCES = \ APL/Exception.cpp \ APL/FlexibleDataObserver.cpp \ APL/IHandlerAsync.cpp \ + APL/ITimerSource.cpp \ APL/IOService.cpp \ APL/IOServiceThread.cpp \ APL/LockBase.cpp \ @@ -415,6 +416,7 @@ dnp3test_SOURCES = \ APLTestTools/MockTimerSource.cpp \ APLTestTools/MockUpperLayer.cpp \ DNP3Test/AppLayerTest.cpp \ + DNP3Test/ComparingDataObserver.cpp \ DNP3Test/DNPHelpers.cpp \ DNP3Test/IntegrationTest.cpp \ DNP3Test/LinkLayerRouterTest.cpp \ From 2fc533fb149224ebb5e436cc68d5fb707e9a2548 Mon Sep 17 00:00:00 2001 From: jadamcrain Date: Fri, 15 Jul 2011 17:14:46 -0400 Subject: [PATCH 9/9] Updated changelog --- CHANGELOG.markdown | 10 ++++++---- ChangeLog | 0 2 files changed, 6 insertions(+), 4 deletions(-) delete mode 100644 ChangeLog diff --git a/CHANGELOG.markdown b/CHANGELOG.markdown index 7a3dc838..cbbeddb0 100644 --- a/CHANGELOG.markdown +++ b/CHANGELOG.markdown @@ -2,16 +2,18 @@ Change Log ============== ### 0.9.5 ### -- Added Virtual Terminal Object (VTO) support with standard implementation and experimental stream support - Migrated to Boost 1.47.0 +- Added Virtual Terminal Object (VTO) support with standard implementation and experimental stream support - Migrated all external numeric types to use boost type definitions for interoperability - Added autotools support thanks to Chris Verges - Rake may be replaced entirely with autotools in a future release -- Added Astyle code formatter to project build system(s) -- Master/Slave can now both notify of their current state using enumeration +- Added Astyle code formatter to project build systems +- Master/Slave can now both notify of their current state using an enumeration - TestSet includes address scanning feature to detect devices that don't support broadcast addressing - sub-Masters on same channel can now use same address if talking to different slaves - Log messages can now contain well known key-value pairs -- Fixes bugs: 18, 15, 9, 7 +- Management class 'AsyncStackManager' now automatically runs when stacks are added, no Start() call +- AsyncStackManger blocks when RemovePort() or RemoveStack() are called until the operation has completed +- Fixed bugs: 18, 15, 9, 7 ### 0.9.4 ### Rebased java namespace to org.totalgrid.reef.protocol.dnp3 diff --git a/ChangeLog b/ChangeLog deleted file mode 100644 index e69de29b..00000000