From 4c01c5cc55e5840ab91d6d51248b080b869f8c17 Mon Sep 17 00:00:00 2001 From: "michal.szwaj" Date: Wed, 4 Apr 2018 18:26:20 +0200 Subject: [PATCH 1/4] Set socket options to detect broken connection --- src/autoapp/UI/ConnectDialog.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/autoapp/UI/ConnectDialog.cpp b/src/autoapp/UI/ConnectDialog.cpp index 127e216..08b4f56 100644 --- a/src/autoapp/UI/ConnectDialog.cpp +++ b/src/autoapp/UI/ConnectDialog.cpp @@ -46,6 +46,8 @@ void ConnectDialog::onConnectButtonClicked() try { + tcpWrapper_.setKeepAliveOption(*socket, true); + tcpWrapper_.setNoDelayOption(*socket, true); tcpWrapper_.asyncConnect(*socket, ipAddress, 5277, std::bind(&ConnectDialog::connectHandler, this, std::placeholders::_1, ipAddress, socket)); } catch(const boost::system::system_error& se) From cf3a5e51d7ec45a02b3a8854657cc270c3893c5a Mon Sep 17 00:00:00 2001 From: "michal.szwaj" Date: Thu, 5 Apr 2018 18:09:15 +0200 Subject: [PATCH 2/4] Draft of ping implementation --- .../autoapp/Projection/AndroidAutoEntity.hpp | 7 +- .../openauto/autoapp/Projection/IPinger.hpp | 47 ++++++++++ .../openauto/autoapp/Projection/Pinger.hpp | 57 ++++++++++++ src/autoapp/Projection/AndroidAutoEntity.cpp | 40 +++++++-- .../Projection/AndroidAutoEntityFactory.cpp | 4 +- src/autoapp/Projection/Pinger.cpp | 86 +++++++++++++++++++ src/autoapp/UI/ConnectDialog.cpp | 2 - 7 files changed, 234 insertions(+), 9 deletions(-) create mode 100644 include/f1x/openauto/autoapp/Projection/IPinger.hpp create mode 100644 include/f1x/openauto/autoapp/Projection/Pinger.hpp create mode 100644 src/autoapp/Projection/Pinger.cpp diff --git a/include/f1x/openauto/autoapp/Projection/AndroidAutoEntity.hpp b/include/f1x/openauto/autoapp/Projection/AndroidAutoEntity.hpp index b085d5e..786ee77 100644 --- a/include/f1x/openauto/autoapp/Projection/AndroidAutoEntity.hpp +++ b/include/f1x/openauto/autoapp/Projection/AndroidAutoEntity.hpp @@ -26,6 +26,7 @@ #include #include #include +#include namespace f1x { @@ -43,7 +44,8 @@ public: aasdk::messenger::ICryptor::Pointer cryptor, aasdk::transport::ITransport::Pointer transport, configuration::IConfiguration::Pointer configuration, - IServiceFactory& serviceFactory); + IServiceFactory& serviceFactory, + IPinger::Pointer pinger); ~AndroidAutoEntity() override; void start(IAndroidAutoEntityEventHandler& eventHandler) override; @@ -55,17 +57,20 @@ public: void onShutdownRequest(const aasdk::proto::messages::ShutdownRequest& request) override; void onShutdownResponse(const aasdk::proto::messages::ShutdownResponse& response) override; void onNavigationFocusRequest(const aasdk::proto::messages::NavigationFocusRequest& request) override; + void onPingResponse(const aasdk::proto::messages::PingResponse& response) override; void onChannelError(const aasdk::error::Error& e) override; private: using std::enable_shared_from_this::shared_from_this; void triggerQuit(); + void ping(); boost::asio::io_service::strand strand_; aasdk::messenger::ICryptor::Pointer cryptor_; aasdk::transport::ITransport::Pointer transport_; configuration::IConfiguration::Pointer configuration_; IServiceFactory& serviceFactory_; + IPinger::Pointer pinger_; aasdk::messenger::IMessenger::Pointer messenger_; aasdk::channel::control::ControlServiceChannel::Pointer controlServiceChannel_; ServiceList serviceList_; diff --git a/include/f1x/openauto/autoapp/Projection/IPinger.hpp b/include/f1x/openauto/autoapp/Projection/IPinger.hpp new file mode 100644 index 0000000..63def2b --- /dev/null +++ b/include/f1x/openauto/autoapp/Projection/IPinger.hpp @@ -0,0 +1,47 @@ +/* +* This file is part of openauto project. +* Copyright (C) 2018 f1x.studio (Michal Szwaj) +* +* openauto is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3 of the License, or +* (at your option) any later version. + +* openauto is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with openauto. If not, see . +*/ + +#pragma once + +#include + +namespace f1x +{ +namespace openauto +{ +namespace autoapp +{ +namespace projection +{ + +class IPinger +{ +public: + typedef std::shared_ptr Pointer; + typedef aasdk::io::Promise Promise; + + virtual ~IPinger() = default; + virtual void ping(Promise::Pointer promise) = 0; + virtual void pong() = 0; + virtual void cancel() = 0; +}; + +} +} +} +} diff --git a/include/f1x/openauto/autoapp/Projection/Pinger.hpp b/include/f1x/openauto/autoapp/Projection/Pinger.hpp new file mode 100644 index 0000000..8ddaafc --- /dev/null +++ b/include/f1x/openauto/autoapp/Projection/Pinger.hpp @@ -0,0 +1,57 @@ +/* +* This file is part of openauto project. +* Copyright (C) 2018 f1x.studio (Michal Szwaj) +* +* openauto is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3 of the License, or +* (at your option) any later version. + +* openauto is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with openauto. If not, see . +*/ + +#pragma once + +#include + +namespace f1x +{ +namespace openauto +{ +namespace autoapp +{ +namespace projection +{ + +class Pinger: public IPinger, std::enable_shared_from_this +{ +public: + Pinger(boost::asio::io_service& ioService, time_t duration); + + void ping(Promise::Pointer promise) override; + void pong() override; + void cancel() override; + +private: + using std::enable_shared_from_this::shared_from_this; + + void onTimerExceeded(const boost::system::error_code& error); + + boost::asio::io_service::strand strand_; + boost::asio::deadline_timer timer_; + time_t duration_; + Promise::Pointer promise_; + int64_t pingsCount_; + int64_t pongsCount_; +}; + +} +} +} +} diff --git a/src/autoapp/Projection/AndroidAutoEntity.cpp b/src/autoapp/Projection/AndroidAutoEntity.cpp index a0c690c..5e77ba0 100644 --- a/src/autoapp/Projection/AndroidAutoEntity.cpp +++ b/src/autoapp/Projection/AndroidAutoEntity.cpp @@ -35,12 +35,14 @@ AndroidAutoEntity::AndroidAutoEntity(boost::asio::io_service& ioService, aasdk::messenger::ICryptor::Pointer cryptor, aasdk::transport::ITransport::Pointer transport, configuration::IConfiguration::Pointer configuration, - IServiceFactory& serviceFactory) + IServiceFactory& serviceFactory, + IPinger::Pointer pinger) : strand_(ioService) , cryptor_(std::move(cryptor)) , transport_(std::move(transport)) , configuration_(std::move(configuration)) , serviceFactory_(serviceFactory) + , pinger_(std::move(pinger)) , messenger_(std::make_shared(ioService, std::make_shared(ioService, transport_, cryptor_), std::make_shared(ioService, transport_, cryptor_))) @@ -178,6 +180,8 @@ void AndroidAutoEntity::onServiceDiscoveryRequest(const aasdk::proto::messages:: promise->then([]() {}, std::bind(&AndroidAutoEntity::onChannelError, this->shared_from_this(), std::placeholders::_1)); controlServiceChannel_->sendServiceDiscoveryResponse(serviceDiscoveryResponse, std::move(promise)); controlServiceChannel_->receive(this->shared_from_this()); + + this->ping(); } void AndroidAutoEntity::onAudioFocusRequest(const aasdk::proto::messages::AudioFocusRequest& request) @@ -205,10 +209,8 @@ void AndroidAutoEntity::onShutdownRequest(const aasdk::proto::messages::Shutdown aasdk::proto::messages::ShutdownResponse response; auto promise = aasdk::channel::SendPromise::defer(strand_); - promise->then([this, self = this->shared_from_this()]() { - this->triggerQuit(); - }, - std::bind(&AndroidAutoEntity::onChannelError, this->shared_from_this(), std::placeholders::_1)); + promise->then(std::bind(&AndroidAutoEntity::triggerQuit, this->shared_from_this()), + std::bind(&AndroidAutoEntity::onChannelError, this->shared_from_this(), std::placeholders::_1)); controlServiceChannel_->sendShutdownResponse(response, std::move(promise)); controlServiceChannel_->receive(this->shared_from_this()); @@ -233,6 +235,14 @@ void AndroidAutoEntity::onNavigationFocusRequest(const aasdk::proto::messages::N controlServiceChannel_->receive(this->shared_from_this()); } +void AndroidAutoEntity::onPingResponse(const aasdk::proto::messages::PingResponse&) +{ + OPENAUTO_LOG(info) << "[AndroidAutoEntity] ping response"; + + pinger_->pong(); + controlServiceChannel_->receive(this->shared_from_this()); +} + void AndroidAutoEntity::onChannelError(const aasdk::error::Error& e) { OPENAUTO_LOG(error) << "[AndroidAutoEntity] channel error: " << e.what(); @@ -247,6 +257,26 @@ void AndroidAutoEntity::triggerQuit() } } +void AndroidAutoEntity::ping() +{ + auto promise = IPinger::Promise::defer(strand_); + promise->then([this, self = this->shared_from_this()]() { + auto promise = aasdk::channel::SendPromise::defer(strand_); + promise->then([]() {}, std::bind(&AndroidAutoEntity::onChannelError, this->shared_from_this(), std::placeholders::_1)); + + aasdk::proto::messages::PingRequest request; + controlServiceChannel_->sendPingRequest(request, std::move(promise)); + + this->ping(); + }, + [this, self = this->shared_from_this()]() { + OPENAUTO_LOG(error) << "[AndroidAutoEntity] ping timer exceeded."; + this->triggerQuit(); + }); + + pinger_->ping(std::move(promise)); +} + } } } diff --git a/src/autoapp/Projection/AndroidAutoEntityFactory.cpp b/src/autoapp/Projection/AndroidAutoEntityFactory.cpp index 0eb6942..a704d03 100644 --- a/src/autoapp/Projection/AndroidAutoEntityFactory.cpp +++ b/src/autoapp/Projection/AndroidAutoEntityFactory.cpp @@ -23,6 +23,7 @@ #include #include #include +#include namespace f1x { @@ -59,8 +60,9 @@ IAndroidAutoEntity::Pointer AndroidAutoEntityFactory::create(aasdk::transport::I { auto sslWrapper(std::make_shared()); auto cryptor(std::make_shared(std::move(sslWrapper))); + auto pinger(std::make_shared(ioService_, 5000)); - return std::make_shared(ioService_, std::move(cryptor), std::move(transport), configuration_, serviceFactory_); + return std::make_shared(ioService_, std::move(cryptor), std::move(transport), configuration_, serviceFactory_, std::move(pinger)); } } diff --git a/src/autoapp/Projection/Pinger.cpp b/src/autoapp/Projection/Pinger.cpp new file mode 100644 index 0000000..7dd5284 --- /dev/null +++ b/src/autoapp/Projection/Pinger.cpp @@ -0,0 +1,86 @@ +/* +* This file is part of openauto project. +* Copyright (C) 2018 f1x.studio (Michal Szwaj) +* +* openauto is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3 of the License, or +* (at your option) any later version. + +* openauto is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with openauto. If not, see . +*/ + +#include + +namespace f1x +{ +namespace openauto +{ +namespace autoapp +{ +namespace projection +{ + +Pinger::Pinger(boost::asio::io_service& ioService, time_t duration) + : strand_(ioService) + , timer_(ioService) + , duration_(duration) + , pingsCount_(0) + , pongsCount_(0) +{ + +} + +void Pinger::ping(Promise::Pointer promise) +{ + strand_.dispatch([this, self = this->shared_from_this(), promise = std::move(promise)]() mutable { + ++pingsCount_; + + promise_ = std::move(promise); + timer_.expires_from_now(boost::posix_time::milliseconds(duration_)); + timer_.async_wait(strand_.wrap(std::bind(&Pinger::onTimerExceeded, this->shared_from_this(), std::placeholders::_1))); + }); +} + +void Pinger::pong() +{ + strand_.dispatch([this, self = this->shared_from_this()]() { + ++pongsCount_; + }); +} + +void Pinger::onTimerExceeded(const boost::system::error_code& error) +{ + if(!error && promise_ != nullptr) + { + if(std::abs(pingsCount_ - pongsCount_) > 1) + { + promise_->reject(); + } + else + { + promise_->resolve(); + } + + promise_.reset(); + } +} + +void Pinger::cancel() +{ + strand_.dispatch([this, self = this->shared_from_this()]() { + promise_.reset(); + timer_.cancel(); + }); +} + +} +} +} +} diff --git a/src/autoapp/UI/ConnectDialog.cpp b/src/autoapp/UI/ConnectDialog.cpp index 08b4f56..127e216 100644 --- a/src/autoapp/UI/ConnectDialog.cpp +++ b/src/autoapp/UI/ConnectDialog.cpp @@ -46,8 +46,6 @@ void ConnectDialog::onConnectButtonClicked() try { - tcpWrapper_.setKeepAliveOption(*socket, true); - tcpWrapper_.setNoDelayOption(*socket, true); tcpWrapper_.asyncConnect(*socket, ipAddress, 5277, std::bind(&ConnectDialog::connectHandler, this, std::placeholders::_1, ipAddress, socket)); } catch(const boost::system::system_error& se) From a0b241802219288c694f5ac0d2c72958f00adf45 Mon Sep 17 00:00:00 2001 From: "michal.szwaj" Date: Thu, 5 Apr 2018 18:27:31 +0200 Subject: [PATCH 3/4] Fix invalid inheritance of enable_shared_from_this --- include/f1x/openauto/autoapp/Projection/Pinger.hpp | 2 +- src/autoapp/Projection/AndroidAutoEntity.cpp | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/include/f1x/openauto/autoapp/Projection/Pinger.hpp b/include/f1x/openauto/autoapp/Projection/Pinger.hpp index 8ddaafc..5c111eb 100644 --- a/include/f1x/openauto/autoapp/Projection/Pinger.hpp +++ b/include/f1x/openauto/autoapp/Projection/Pinger.hpp @@ -29,7 +29,7 @@ namespace autoapp namespace projection { -class Pinger: public IPinger, std::enable_shared_from_this +class Pinger: public IPinger, public std::enable_shared_from_this { public: Pinger(boost::asio::io_service& ioService, time_t duration); diff --git a/src/autoapp/Projection/AndroidAutoEntity.cpp b/src/autoapp/Projection/AndroidAutoEntity.cpp index 5e77ba0..7e9c0d1 100644 --- a/src/autoapp/Projection/AndroidAutoEntity.cpp +++ b/src/autoapp/Projection/AndroidAutoEntity.cpp @@ -79,8 +79,8 @@ void AndroidAutoEntity::stop() strand_.dispatch([this, self = this->shared_from_this()]() { OPENAUTO_LOG(info) << "[AndroidAutoEntity] stop."; + pinger_->cancel(); std::for_each(serviceList_.begin(), serviceList_.end(), std::bind(&IService::stop, std::placeholders::_1)); - messenger_->stop(); cryptor_->deinit(); transport_->stop(); @@ -145,6 +145,7 @@ void AndroidAutoEntity::onHandshake(const aasdk::common::DataConstBuffer& payloa auto authCompletePromise = aasdk::channel::SendPromise::defer(strand_); authCompletePromise->then([]() {}, std::bind(&AndroidAutoEntity::onChannelError, this->shared_from_this(), std::placeholders::_1)); controlServiceChannel_->sendAuthComplete(authCompleteIndication, std::move(authCompletePromise)); + this->ping(); } controlServiceChannel_->receive(this->shared_from_this()); @@ -180,8 +181,6 @@ void AndroidAutoEntity::onServiceDiscoveryRequest(const aasdk::proto::messages:: promise->then([]() {}, std::bind(&AndroidAutoEntity::onChannelError, this->shared_from_this(), std::placeholders::_1)); controlServiceChannel_->sendServiceDiscoveryResponse(serviceDiscoveryResponse, std::move(promise)); controlServiceChannel_->receive(this->shared_from_this()); - - this->ping(); } void AndroidAutoEntity::onAudioFocusRequest(const aasdk::proto::messages::AudioFocusRequest& request) @@ -237,8 +236,6 @@ void AndroidAutoEntity::onNavigationFocusRequest(const aasdk::proto::messages::N void AndroidAutoEntity::onPingResponse(const aasdk::proto::messages::PingResponse&) { - OPENAUTO_LOG(info) << "[AndroidAutoEntity] ping response"; - pinger_->pong(); controlServiceChannel_->receive(this->shared_from_this()); } @@ -266,7 +263,6 @@ void AndroidAutoEntity::ping() aasdk::proto::messages::PingRequest request; controlServiceChannel_->sendPingRequest(request, std::move(promise)); - this->ping(); }, [this, self = this->shared_from_this()]() { From 28fc6a32e947231a29249b5de2fe3c595edfcfe5 Mon Sep 17 00:00:00 2001 From: "michal.szwaj" Date: Thu, 5 Apr 2018 23:33:38 +0200 Subject: [PATCH 4/4] Standarize behavior of pinger cancel --- .../openauto/autoapp/Projection/IPinger.hpp | 2 +- .../openauto/autoapp/Projection/Pinger.hpp | 1 + src/autoapp/App.cpp | 4 +- src/autoapp/Projection/AndroidAutoEntity.cpp | 19 ++++---- src/autoapp/Projection/Pinger.cpp | 47 ++++++++++++------- 5 files changed, 46 insertions(+), 27 deletions(-) diff --git a/include/f1x/openauto/autoapp/Projection/IPinger.hpp b/include/f1x/openauto/autoapp/Projection/IPinger.hpp index 63def2b..379462f 100644 --- a/include/f1x/openauto/autoapp/Projection/IPinger.hpp +++ b/include/f1x/openauto/autoapp/Projection/IPinger.hpp @@ -33,7 +33,7 @@ class IPinger { public: typedef std::shared_ptr Pointer; - typedef aasdk::io::Promise Promise; + typedef aasdk::io::Promise Promise; virtual ~IPinger() = default; virtual void ping(Promise::Pointer promise) = 0; diff --git a/include/f1x/openauto/autoapp/Projection/Pinger.hpp b/include/f1x/openauto/autoapp/Projection/Pinger.hpp index 5c111eb..bc7884f 100644 --- a/include/f1x/openauto/autoapp/Projection/Pinger.hpp +++ b/include/f1x/openauto/autoapp/Projection/Pinger.hpp @@ -46,6 +46,7 @@ private: boost::asio::io_service::strand strand_; boost::asio::deadline_timer timer_; time_t duration_; + bool cancelled_; Promise::Pointer promise_; int64_t pingsCount_; int64_t pongsCount_; diff --git a/src/autoapp/App.cpp b/src/autoapp/App.cpp index b3f92a0..26274c7 100644 --- a/src/autoapp/App.cpp +++ b/src/autoapp/App.cpp @@ -165,8 +165,8 @@ void App::onUSBHubError(const aasdk::error::Error& error) { OPENAUTO_LOG(error) << "[App] usb hub error: " << error.what(); - if(error.getCode() != aasdk::error::ErrorCode::OPERATION_ABORTED && - error.getCode() != aasdk::error::ErrorCode::OPERATION_IN_PROGRESS) + if(error != aasdk::error::ErrorCode::OPERATION_ABORTED && + error != aasdk::error::ErrorCode::OPERATION_IN_PROGRESS) { this->waitForDevice(); } diff --git a/src/autoapp/Projection/AndroidAutoEntity.cpp b/src/autoapp/Projection/AndroidAutoEntity.cpp index 7e9c0d1..b36bb29 100644 --- a/src/autoapp/Projection/AndroidAutoEntity.cpp +++ b/src/autoapp/Projection/AndroidAutoEntity.cpp @@ -60,17 +60,18 @@ void AndroidAutoEntity::start(IAndroidAutoEntityEventHandler& eventHandler) { strand_.dispatch([this, self = this->shared_from_this(), eventHandler = &eventHandler]() { OPENAUTO_LOG(info) << "[AndroidAutoEntity] start."; - eventHandler_ = eventHandler; cryptor_->init(); serviceList_ = serviceFactory_.create(messenger_); std::for_each(serviceList_.begin(), serviceList_.end(), std::bind(&IService::start, std::placeholders::_1)); + this->ping(); - controlServiceChannel_->receive(this->shared_from_this()); auto versionRequestPromise = aasdk::channel::SendPromise::defer(strand_); versionRequestPromise->then([]() {}, std::bind(&AndroidAutoEntity::onChannelError, this->shared_from_this(), std::placeholders::_1)); controlServiceChannel_->sendVersionRequest(std::move(versionRequestPromise)); + eventHandler_ = eventHandler; + controlServiceChannel_->receive(this->shared_from_this()); }); } @@ -79,12 +80,12 @@ void AndroidAutoEntity::stop() strand_.dispatch([this, self = this->shared_from_this()]() { OPENAUTO_LOG(info) << "[AndroidAutoEntity] stop."; + eventHandler_ = nullptr; pinger_->cancel(); std::for_each(serviceList_.begin(), serviceList_.end(), std::bind(&IService::stop, std::placeholders::_1)); messenger_->stop(); cryptor_->deinit(); transport_->stop(); - eventHandler_ = nullptr; }); } @@ -145,7 +146,6 @@ void AndroidAutoEntity::onHandshake(const aasdk::common::DataConstBuffer& payloa auto authCompletePromise = aasdk::channel::SendPromise::defer(strand_); authCompletePromise->then([]() {}, std::bind(&AndroidAutoEntity::onChannelError, this->shared_from_this(), std::placeholders::_1)); controlServiceChannel_->sendAuthComplete(authCompleteIndication, std::move(authCompletePromise)); - this->ping(); } controlServiceChannel_->receive(this->shared_from_this()); @@ -212,7 +212,6 @@ void AndroidAutoEntity::onShutdownRequest(const aasdk::proto::messages::Shutdown std::bind(&AndroidAutoEntity::onChannelError, this->shared_from_this(), std::placeholders::_1)); controlServiceChannel_->sendShutdownResponse(response, std::move(promise)); - controlServiceChannel_->receive(this->shared_from_this()); } void AndroidAutoEntity::onShutdownResponse(const aasdk::proto::messages::ShutdownResponse&) @@ -265,9 +264,13 @@ void AndroidAutoEntity::ping() controlServiceChannel_->sendPingRequest(request, std::move(promise)); this->ping(); }, - [this, self = this->shared_from_this()]() { - OPENAUTO_LOG(error) << "[AndroidAutoEntity] ping timer exceeded."; - this->triggerQuit(); + [this, self = this->shared_from_this()](auto error) { + if(error != aasdk::error::ErrorCode::OPERATION_ABORTED && + error != aasdk::error::ErrorCode::OPERATION_IN_PROGRESS) + { + OPENAUTO_LOG(error) << "[AndroidAutoEntity] ping timer exceeded."; + this->triggerQuit(); + } }); pinger_->ping(std::move(promise)); diff --git a/src/autoapp/Projection/Pinger.cpp b/src/autoapp/Projection/Pinger.cpp index 7dd5284..8be0cde 100644 --- a/src/autoapp/Projection/Pinger.cpp +++ b/src/autoapp/Projection/Pinger.cpp @@ -31,6 +31,7 @@ Pinger::Pinger(boost::asio::io_service& ioService, time_t duration) : strand_(ioService) , timer_(ioService) , duration_(duration) + , cancelled_(false) , pingsCount_(0) , pongsCount_(0) { @@ -40,11 +41,20 @@ Pinger::Pinger(boost::asio::io_service& ioService, time_t duration) void Pinger::ping(Promise::Pointer promise) { strand_.dispatch([this, self = this->shared_from_this(), promise = std::move(promise)]() mutable { - ++pingsCount_; + cancelled_ = false; - promise_ = std::move(promise); - timer_.expires_from_now(boost::posix_time::milliseconds(duration_)); - timer_.async_wait(strand_.wrap(std::bind(&Pinger::onTimerExceeded, this->shared_from_this(), std::placeholders::_1))); + if(promise_ != nullptr) + { + promise_->reject(aasdk::error::Error(aasdk::error::ErrorCode::OPERATION_IN_PROGRESS)); + } + else + { + ++pingsCount_; + + promise_ = std::move(promise); + timer_.expires_from_now(boost::posix_time::milliseconds(duration_)); + timer_.async_wait(strand_.wrap(std::bind(&Pinger::onTimerExceeded, this->shared_from_this(), std::placeholders::_1))); + } }); } @@ -57,25 +67,30 @@ void Pinger::pong() void Pinger::onTimerExceeded(const boost::system::error_code& error) { - if(!error && promise_ != nullptr) + if(promise_ == nullptr) { - if(std::abs(pingsCount_ - pongsCount_) > 1) - { - promise_->reject(); - } - else - { - promise_->resolve(); - } - - promise_.reset(); + return; } + else if(error == boost::asio::error::operation_aborted || cancelled_) + { + promise_->reject(aasdk::error::Error(aasdk::error::ErrorCode::OPERATION_ABORTED)); + } + else if(pingsCount_ - pongsCount_ > 1) + { + promise_->reject(aasdk::error::Error()); + } + else + { + promise_->resolve(); + } + + promise_.reset(); } void Pinger::cancel() { strand_.dispatch([this, self = this->shared_from_this()]() { - promise_.reset(); + cancelled_ = true; timer_.cancel(); }); }