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..379462f --- /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..bc7884f --- /dev/null +++ b/include/f1x/openauto/autoapp/Projection/Pinger.hpp @@ -0,0 +1,58 @@ +/* +* 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, public 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_; + 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 a0c690c..b36bb29 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_))) @@ -58,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()); }); } @@ -77,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; }); } @@ -205,13 +208,10 @@ 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()); } void AndroidAutoEntity::onShutdownResponse(const aasdk::proto::messages::ShutdownResponse&) @@ -233,6 +233,12 @@ void AndroidAutoEntity::onNavigationFocusRequest(const aasdk::proto::messages::N controlServiceChannel_->receive(this->shared_from_this()); } +void AndroidAutoEntity::onPingResponse(const aasdk::proto::messages::PingResponse&) +{ + 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 +253,29 @@ 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()](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/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..8be0cde --- /dev/null +++ b/src/autoapp/Projection/Pinger.cpp @@ -0,0 +1,101 @@ +/* +* 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) + , cancelled_(false) + , pingsCount_(0) + , pongsCount_(0) +{ + +} + +void Pinger::ping(Promise::Pointer promise) +{ + strand_.dispatch([this, self = this->shared_from_this(), promise = std::move(promise)]() mutable { + cancelled_ = false; + + 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))); + } + }); +} + +void Pinger::pong() +{ + strand_.dispatch([this, self = this->shared_from_this()]() { + ++pongsCount_; + }); +} + +void Pinger::onTimerExceeded(const boost::system::error_code& error) +{ + if(promise_ == nullptr) + { + 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()]() { + cancelled_ = true; + timer_.cancel(); + }); +} + +} +} +} +}