Thanks to visit codestin.com
Credit goes to github.com

Skip to content
This repository was archived by the owner on Sep 1, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ jobs:
matrix:
build-type: [Debug, Release]
architecture: [x86, x64]
runs-on: windows-latest
runs-on: windows-2019
steps:
- name: Checkout
uses: actions/checkout@v2
Expand All @@ -98,7 +98,7 @@ jobs:
if("${{ matrix.architecture }}" -eq "x86") { $flag = "--x86" } else { $flag = "" };
choco install --no-progress "$flag" cmake.portable nuget.commandline openssl; mkdir build
- name: Install Java
uses: actions/setup-java@v1.4.3
uses: actions/setup-java@v1
with:
java-version: 8
java-package: jdk
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
### Next ###
* :beetle: Fix `PrintingSOEHandler` octet string size not printing properly.
See [4372862](https://github.com/dnp3/opendnp3/commit/4372862728851f559a01edcd88bc15ce6ce7f350)
* :beetle: Fix keep-alive timer not properly calculated. See [#407](https://github.com/dnp3/opendnp3/pull/407).
* :beetle: Fix `LinkContext` and `MContext` possible lifetime issue.
See [#407](https://github.com/dnp3/opendnp3/pull/407).

### 3.1.1 ###
* :beetle: Fix static octet string serilazation bug.
Expand Down
75 changes: 41 additions & 34 deletions cpp/lib/src/link/LinkContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,16 @@ LinkContext::LinkContext(const Logger& logger,
{
}

std::shared_ptr<LinkContext> LinkContext::Create(const Logger& logger,
const std::shared_ptr<exe4cpp::IExecutor>& executor,
std::shared_ptr<IUpperLayer> upper,
std::shared_ptr<ILinkListener> listener,
ILinkSession& session,
const LinkLayerConfig& config)
{
return std::shared_ptr<LinkContext>(new LinkContext(logger, executor, upper, listener, session, config));
}

bool LinkContext::OnLowerLayerUp()
{
if (this->isOnline)
Expand All @@ -58,13 +68,9 @@ bool LinkContext::OnLowerLayerUp()
return false;
}

const auto now = Timestamp(this->executor->get_time());

this->isOnline = true;

this->lastMessageTimestamp = now; // no reason to trigger a keep-alive until we've actually expired

this->StartKeepAliveTimer(now + config.KeepAliveTimeout);
this->RestartKeepAliveTimer();

listener->OnStateChange(LinkStatus::UNRESET);
upper->OnLowerLayerUp();
Expand Down Expand Up @@ -230,16 +236,14 @@ void LinkContext::TryStartTransmission()
void LinkContext::OnKeepAliveTimeout()
{
const auto now = Timestamp(this->executor->get_time());

auto elapsed = now - this->lastMessageTimestamp;
const auto elapsed = now - this->lastMessageTimestamp;

if (elapsed >= this->config.KeepAliveTimeout)
{
this->lastMessageTimestamp = now;
this->keepAliveTimeout = true;
}

this->StartKeepAliveTimer(now + config.KeepAliveTimeout);
this->RestartKeepAliveTimer();

this->TryStartTransmission();
}
Expand All @@ -253,12 +257,27 @@ void LinkContext::OnResponseTimeout()

void LinkContext::StartResponseTimer()
{
rspTimeoutTimer = executor->start(config.Timeout.value, [this]() { this->OnResponseTimeout(); });
this->rspTimeoutTimer = executor->start(config.Timeout.value, [self = shared_from_this()]() {
if (self->isOnline)
{
self->OnResponseTimeout();
}
});
}

void LinkContext::StartKeepAliveTimer(const Timestamp& expiration)
void LinkContext::RestartKeepAliveTimer()
{
this->keepAliveTimer = executor->start(expiration.value, [this]() { this->OnKeepAliveTimeout(); });
this->keepAliveTimer.cancel();

this->lastMessageTimestamp = Timestamp(this->executor->get_time());
const auto expiration = this->lastMessageTimestamp + this->config.KeepAliveTimeout;

this->keepAliveTimer = executor->start(expiration.value, [self = shared_from_this()]() {
if (self->isOnline)
{
self->OnKeepAliveTimeout();
}
});
}

void LinkContext::CancelTimer()
Expand Down Expand Up @@ -310,31 +329,19 @@ bool LinkContext::OnFrame(const LinkHeaderFields& header, const ser4cpp::rseq_t&
return false;
}

if (header.addresses.IsBroadcast())
// Broadcast addresses can only be used for sending data.
// If confirmed data is used, no response is sent back.
if (header.addresses.IsBroadcast() &&
!(header.func == LinkFunction::PRI_UNCONFIRMED_USER_DATA || header.func == LinkFunction::PRI_CONFIRMED_USER_DATA))
{
// Broadcast addresses can only be used for sending data.
// If confirmed data is used, no response is sent back.
if (header.func == LinkFunction::PRI_UNCONFIRMED_USER_DATA)
{
this->PushDataUp(Message(header.addresses, userdata));
return true;
}
else if (header.func == LinkFunction::PRI_CONFIRMED_USER_DATA)
{
pSecState = &pSecState->OnConfirmedUserData(*this, header.addresses.source, header.fcb, true,
Message(header.addresses, userdata));
}
else
{
FORMAT_LOG_BLOCK(logger, flags::WARN, "Received invalid function (%s) with broadcast destination address",
LinkFunctionSpec::to_string(header.func));
++statistics.numUnexpectedFrame;
return false;
}
FORMAT_LOG_BLOCK(logger, flags::WARN, "Received invalid function (%s) with broadcast destination address",
LinkFunctionSpec::to_string(header.func));
++statistics.numUnexpectedFrame;
return false;
}

// reset the keep-alive timestamp
this->lastMessageTimestamp = Timestamp(this->executor->get_time());
this->RestartKeepAliveTimer();

switch (header.func)
{
Expand All @@ -360,7 +367,7 @@ bool LinkContext::OnFrame(const LinkHeaderFields& header, const ser4cpp::rseq_t&
pSecState = &pSecState->OnRequestLinkStatus(*this, header.addresses.source);
break;
case (LinkFunction::PRI_CONFIRMED_USER_DATA):
pSecState = &pSecState->OnConfirmedUserData(*this, header.addresses.source, header.fcb, false,
pSecState = &pSecState->OnConfirmedUserData(*this, header.addresses.source, header.fcb, header.addresses.IsBroadcast(),
Message(header.addresses, userdata));
break;
case (LinkFunction::PRI_UNCONFIRMED_USER_DATA):
Expand Down
16 changes: 12 additions & 4 deletions cpp/lib/src/link/LinkContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@

#include <exe4cpp/IExecutor.h>

#include <memory>

namespace opendnp3
{

Expand All @@ -51,17 +53,23 @@ enum class LinkTransmitMode : uint8_t
};

// @section desc Implements the contextual state of DNP3 Data Link Layer
class LinkContext
class LinkContext : public std::enable_shared_from_this<LinkContext>
{

public:
LinkContext(const Logger& logger,
const std::shared_ptr<exe4cpp::IExecutor>&,
std::shared_ptr<IUpperLayer>,
std::shared_ptr<ILinkListener>,
ILinkSession& session,
const LinkLayerConfig&);

public:
static std::shared_ptr<LinkContext> Create(const Logger& logger,
const std::shared_ptr<exe4cpp::IExecutor>&,
std::shared_ptr<IUpperLayer>,
std::shared_ptr<ILinkListener>,
ILinkSession& session,
const LinkLayerConfig&);

// ---- helpers for dealing with the FCB bits ----

void ResetReadFCB()
Expand Down Expand Up @@ -97,7 +105,7 @@ class LinkContext
void OnKeepAliveTimeout();
void OnResponseTimeout();
void StartResponseTimer();
void StartKeepAliveTimer(const Timestamp& expiration);
void RestartKeepAliveTimer();
void CancelTimer();
void FailKeepAlive(bool timeout);
void CompleteKeepAlive();
Expand Down
26 changes: 13 additions & 13 deletions cpp/lib/src/link/LinkLayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,19 @@ LinkLayer::LinkLayer(const Logger& logger,
const std::shared_ptr<IUpperLayer>& upper,
const std::shared_ptr<ILinkListener>& listener,
const LinkLayerConfig& config)
: ctx(logger, executor, upper, listener, *this, config)
: ctx(LinkContext::Create(logger, executor, upper, listener, *this, config))
{
}

const StackStatistics::Link& LinkLayer::GetStatistics() const
{
return this->ctx.statistics;
return this->ctx->statistics;
}

void LinkLayer::SetRouter(ILinkTx& router)
{
assert(!ctx.linktx);
ctx.linktx = &router;
assert(!ctx->linktx);
ctx->linktx = &router;
}

////////////////////////////////
Expand All @@ -48,12 +48,12 @@ void LinkLayer::SetRouter(ILinkTx& router)

bool LinkLayer::Send(ITransportSegment& segments)
{
if (!ctx.isOnline)
if (!ctx->isOnline)
return false;

if (ctx.SetTxSegment(segments))
if (ctx->SetTxSegment(segments))
{
ctx.TryStartTransmission();
ctx->TryStartTransmission();
}

return true;
Expand All @@ -65,21 +65,21 @@ bool LinkLayer::Send(ITransportSegment& segments)

bool LinkLayer::OnLowerLayerUp()
{
return ctx.OnLowerLayerUp();
return ctx->OnLowerLayerUp();
}

bool LinkLayer::OnLowerLayerDown()
{
return ctx.OnLowerLayerDown();
return ctx->OnLowerLayerDown();
}

bool LinkLayer::OnTxReady()
{
auto ret = ctx.OnTxReady();
auto ret = ctx->OnTxReady();

if (ret)
{
ctx.TryStartTransmission();
ctx->TryStartTransmission();
}

return true;
Expand All @@ -91,11 +91,11 @@ bool LinkLayer::OnTxReady()

bool LinkLayer::OnFrame(const LinkHeaderFields& header, const ser4cpp::rseq_t& userdata)
{
auto ret = this->ctx.OnFrame(header, userdata);
auto ret = this->ctx->OnFrame(header, userdata);

if (ret)
{
this->ctx.TryStartTransmission();
this->ctx->TryStartTransmission();
}

return ret;
Expand Down
4 changes: 3 additions & 1 deletion cpp/lib/src/link/LinkLayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
#include "LinkContext.h"
#include "LinkLayerConfig.h"

#include <memory>

namespace opendnp3
{

Expand Down Expand Up @@ -54,7 +56,7 @@ class LinkLayer final : public ILinkLayer, public ILinkSession

private:
// The full state
LinkContext ctx;
std::shared_ptr<LinkContext> ctx;
};

} // namespace opendnp3
Expand Down
15 changes: 14 additions & 1 deletion cpp/lib/src/master/MasterContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,19 @@ MContext::MContext(const Addresses& addresses,
{
}

std::shared_ptr<MContext> MContext::Create(
const Addresses& addresses,
const Logger& logger,
const std::shared_ptr<exe4cpp::IExecutor>& executor,
std::shared_ptr<ILowerLayer> lower,
const std::shared_ptr<ISOEHandler>& SOEHandler,
const std::shared_ptr<IMasterApplication>& application,
std::shared_ptr<IMasterScheduler> scheduler,
const MasterParams& params)
{
return std::shared_ptr<MContext>(new MContext(addresses, logger, executor, lower, SOEHandler, application, scheduler, params));
}

bool MContext::OnLowerLayerUp()
{
if (isOnline)
Expand Down Expand Up @@ -289,7 +302,7 @@ void MContext::Transmit(const ser4cpp::rseq_t& data)

void MContext::StartResponseTimer()
{
auto timeout = [this]() { this->OnResponseTimeout(); };
auto timeout = [self = shared_from_this()]() { self->OnResponseTimeout(); };
this->responseTimer = this->executor->start(this->params.responseTimeout.value, timeout);
}

Expand Down
30 changes: 21 additions & 9 deletions cpp/lib/src/master/MasterContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,24 @@
#include <exe4cpp/asio/StrandExecutor.h>

#include <deque>
#include <memory>

namespace opendnp3
{
/*
All of the mutable state and configuration for a master
*/
class MContext final : public IUpperLayer, private IMasterTaskRunner, private Uncopyable
class MContext final : public IUpperLayer, public std::enable_shared_from_this<MContext>, private IMasterTaskRunner, private Uncopyable
{
private:
MContext(const Addresses& addresses,
const Logger& logger,
const std::shared_ptr<exe4cpp::IExecutor>& executor,
std::shared_ptr<ILowerLayer> lower,
const std::shared_ptr<ISOEHandler>& SOEHandler,
const std::shared_ptr<IMasterApplication>& application,
std::shared_ptr<IMasterScheduler> scheduler,
const MasterParams& params);

public:
enum class TaskState
Expand All @@ -57,14 +67,16 @@ class MContext final : public IUpperLayer, private IMasterTaskRunner, private Un
WAIT_FOR_RESPONSE
};

MContext(const Addresses& addresses,
const Logger& logger,
const std::shared_ptr<exe4cpp::IExecutor>& executor,
std::shared_ptr<ILowerLayer> lower,
const std::shared_ptr<ISOEHandler>& SOEHandler,
const std::shared_ptr<IMasterApplication>& application,
std::shared_ptr<IMasterScheduler> scheduler,
const MasterParams& params);
static std::shared_ptr<MContext> Create(
const Addresses& addresses,
const Logger& logger,
const std::shared_ptr<exe4cpp::IExecutor>& executor,
std::shared_ptr<ILowerLayer> lower,
const std::shared_ptr<ISOEHandler>& SOEHandler,
const std::shared_ptr<IMasterApplication>& application,
std::shared_ptr<IMasterScheduler> scheduler,
const MasterParams& params
);

Logger logger;
const std::shared_ptr<exe4cpp::IExecutor> executor;
Expand Down
Loading