123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- /*
- * Copyright (c) 2017-2023 zhllxt
- *
- * author : zhllxt
- * email : 37792738@qq.com
- *
- * Distributed under the Boost Software License, Version 1.0. (See accompanying
- * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- */
- #ifndef __ASIO2_SILENCE_TIMER_COMPONENT_HPP__
- #define __ASIO2_SILENCE_TIMER_COMPONENT_HPP__
- #if defined(_MSC_VER) && (_MSC_VER >= 1200)
- #pragma once
- #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
- #include <chrono>
- #include <asio2/base/iopool.hpp>
- #include <asio2/base/log.hpp>
- namespace asio2::detail
- {
- template<class derived_t, class args_t>
- class silence_timer_cp
- {
- public:
- /**
- * @brief constructor
- */
- silence_timer_cp() = default;
- /**
- * @brief destructor
- */
- ~silence_timer_cp() = default;
- public:
- /**
- * @brief get silence timeout value
- */
- inline std::chrono::steady_clock::duration get_silence_timeout() const noexcept
- {
- return this->silence_timeout_;
- }
- /**
- * @brief set silence timeout value
- */
- template<class Rep, class Period>
- inline derived_t & set_silence_timeout(std::chrono::duration<Rep, Period> duration) noexcept
- {
- if (duration > std::chrono::duration_cast<
- std::chrono::duration<Rep, Period>>((std::chrono::steady_clock::duration::max)()))
- this->silence_timeout_ = (std::chrono::steady_clock::duration::max)();
- else
- this->silence_timeout_ = duration;
- return static_cast<derived_t&>(*this);
- }
- protected:
- template<class Rep, class Period>
- inline void _post_silence_timer(
- std::chrono::duration<Rep, Period> duration, std::shared_ptr<derived_t> this_ptr)
- {
- derived_t& derive = static_cast<derived_t&>(*this);
- asio::dispatch(derive.io_->context(), make_allocator(derive.wallocator(),
- [this, this_ptr = std::move(this_ptr), duration]() mutable
- {
- derived_t& derive = static_cast<derived_t&>(*this);
- #if defined(_DEBUG) || defined(DEBUG)
- ASIO2_ASSERT(this->is_stop_silence_timer_called_ == false);
- #endif
- // reset the "canceled" flag to false, see reconnect_timer_cp.hpp -> _make_reconnect_timer
- this->silence_timer_canceled_.clear();
- // start the timer of check silence timeout
- if (duration > std::chrono::duration<Rep, Period>::zero())
- {
- if (this->silence_timer_ == nullptr)
- {
- this->silence_timer_ = std::make_unique<asio::steady_timer>(derive.io_->context());
- }
- this->silence_timer_->expires_after(duration);
- this->silence_timer_->async_wait(
- [&derive, this_ptr = std::move(this_ptr)](const error_code & ec) mutable
- {
- derive._handle_silence_timer(ec, std::move(this_ptr));
- });
- }
- }));
- }
- inline void _handle_silence_timer(const error_code & ec, std::shared_ptr<derived_t> this_ptr)
- {
- derived_t& derive = static_cast<derived_t&>(*this);
- ASIO2_ASSERT((!ec) || ec == asio::error::operation_aborted);
- // ec maybe zero when timer_canceled_ is true.
- if (ec == asio::error::operation_aborted || this->silence_timer_canceled_.test_and_set())
- {
- this->silence_timer_.reset();
- return;
- }
- this->silence_timer_canceled_.clear();
- // silence duration seconds not exceed the silence timeout,post a timer
- // event agagin to avoid this session shared_ptr object disappear.
- std::chrono::system_clock::duration silence = derive.get_silence_duration();
- if (silence < this->silence_timeout_)
- {
- derive._post_silence_timer(this->silence_timeout_ - silence, std::move(this_ptr));
- }
- else
- {
- // silence timeout has elasped,but has't data trans,don't post
- // a timer event again,so this session, shared_ptr will disappear
- // and the object will be destroyed automatically after this handler returns.
- set_last_error(asio::error::timed_out);
- derive._do_disconnect(asio::error::timed_out, std::move(this_ptr));
- this->silence_timer_.reset();
- }
- }
- inline void _stop_silence_timer()
- {
- derived_t& derive = static_cast<derived_t&>(*this);
- derive.dispatch([this]() mutable
- {
- #if defined(_DEBUG) || defined(DEBUG)
- this->is_stop_silence_timer_called_ = true;
- #endif
- this->silence_timer_canceled_.test_and_set();
- if (this->silence_timer_)
- {
- detail::cancel_timer(*(this->silence_timer_));
- }
- });
- }
- protected:
- /// timer for session silence time out
- std::unique_ptr<asio::steady_timer> silence_timer_;
- /// Why use this flag, beacuase the ec param maybe zero when the timer callback is
- /// called after the timer cancel function has called already.
- std::atomic_flag silence_timer_canceled_;
- /// if there has no data transfer for a long time,the session will be disconnect
- std::chrono::steady_clock::duration silence_timeout_ = std::chrono::milliseconds(tcp_silence_timeout);
- #if defined(_DEBUG) || defined(DEBUG)
- bool is_stop_silence_timer_called_ = false;
- #endif
- };
- }
- #endif // !__ASIO2_SILENCE_TIMER_COMPONENT_HPP__
|