/* * 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_SESSION_HPP__ #define __ASIO2_SESSION_HPP__ #if defined(_MSC_VER) && (_MSC_VER >= 1200) #pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace asio2 { class session { public: inline constexpr static bool is_session() noexcept { return true ; } inline constexpr static bool is_client () noexcept { return false; } inline constexpr static bool is_server () noexcept { return false; } }; } namespace asio2::detail { ASIO2_CLASS_FORWARD_DECLARE_BASE; template class session_impl_t : public asio2::session , public object_t , public thread_id_cp , public io_context_cp , public event_queue_cp , public user_data_cp , public connect_time_cp , public alive_time_cp , public socket_cp , public connect_cp , public shutdown_cp , public close_cp , public disconnect_cp , public user_timer_cp , public silence_timer_cp , public connect_timeout_cp , public send_cp , public post_cp , public condition_event_cp , public rdc_call_cp { ASIO2_CLASS_FRIEND_DECLARE_BASE; public: using super = object_t ; using self = session_impl_t; using args_type = args_t; using buffer_type = typename args_t::buffer_t; using send_cp::send; using send_cp::async_send; public: /** * @brief constructor * @throws maybe throw exception "Too many open files" (exception code : 24) * asio::error::no_descriptors - Too many open files */ template explicit session_impl_t( session_mgr_t & sessions, listener_t & listener, std::shared_ptr rwio, std::size_t init_buf_size, std::size_t max_buf_size, Args&&... args ) : super() , thread_id_cp () , io_context_cp (std::move(rwio)) , event_queue_cp () , user_data_cp () , connect_time_cp () , alive_time_cp () , socket_cp (std::forward(args)...) , connect_cp () , shutdown_cp () , close_cp () , disconnect_cp () , user_timer_cp () , silence_timer_cp () , connect_timeout_cp () , send_cp () , post_cp () , condition_event_cp () , rdc_call_cp () , sessions_(sessions) , listener_(listener) , buffer_ (init_buf_size, max_buf_size) { } /** * @brief destructor */ ~session_impl_t() { } protected: /** * @brief start session */ inline void start() { this->derived().dispatch([this]() mutable { // init the running thread id this->derived().io_->init_thread_id(); // start the timer of check connect timeout this->derived()._make_connect_timeout_timer( this->derived().selfptr(), this->connect_timeout_); }); } public: /** * @brief stop session * note : this function must be noblocking,if it's blocking, * will cause circle lock in session_mgr::stop function */ inline void stop() { ASIO2_ASSERT(this->io_->running_in_this_thread()); // can't use post, we need ensure when the derived stop is called, the chain // must be executed completed. this->derived().dispatch([this]() mutable { // close silence timer this->_stop_silence_timer(); // close connect timeout timer this->_stop_connect_timeout_timer(); // close user custom timers this->_dispatch_stop_all_timers(); // close all posted timed tasks this->_dispatch_stop_all_timed_events(); // close all async_events this->notify_all_condition_events(); // clear recv buffer this->buffer().consume(this->buffer().size()); // destroy user data, maybe the user data is self shared_ptr, // if don't destroy it, will cause loop reference. // read/write user data in other thread which is not the io_context // thread maybe cause crash. this->user_data_.reset(); // destroy the ecs, the user maybe saved the session ptr in the match role init // function, so we must destroy ecs, otherwise the server will can't be exited // forever. this->ecs_.reset(); // this->reset_life_id(); // this->counter_ptr_.reset(); ASIO2_ASSERT(this->sessions_.find(this->derived().hash_key()) == nullptr); }); } /** * @brief destroy the content of all member variables, this is used for solve the memory leaks. * After this function is called, this class object cannot be used again. */ inline void destroy() { derived_t& derive = this->derived(); derive.socket_.reset(); derive.io_.reset(); } /** * @brief check whether the session is started */ inline bool is_started() const { return (this->state_ == state_t::started && this->socket().is_open()); } /** * @brief check whether the session is stopped */ inline bool is_stopped() const { return (this->state_ == state_t::stopped && !this->socket().is_open()); } /** * @brief get the buffer object reference */ inline buffer_wrap & buffer() noexcept { return this->buffer_; } /** * @brief set the default remote call timeout for rpc/rdc */ template inline derived_t & set_default_timeout(std::chrono::duration duration) noexcept { this->rc_timeout_ = duration; return (this->derived()); } /** * @brief get the default remote call timeout for rpc/rdc */ inline std::chrono::steady_clock::duration get_default_timeout() const noexcept { return this->rc_timeout_; } protected: inline session_mgr_t & sessions() noexcept { return this->sessions_; } inline listener_t & listener() noexcept { return this->listener_; } inline std::atomic & state () noexcept { return this->state_; } inline constexpr bool life_id () noexcept { return true; } inline constexpr void reset_life_id () noexcept { } protected: /// asio::strand ,used to ensure socket multi thread safe,we must ensure that only one operator /// can operate the same socket at the same time,and strand can enuser that the event will /// be processed in the order of post, eg : strand.post(1);strand.post(2); the 2 will processed /// certaion after the 1,if 1 is block,the 2 won't be processed,util the 1 is processed completed /// more details see : http://bbs.csdn.net/topics/390931471 /// session_mgr session_mgr_t & sessions_; /// listener listener_t & listener_; /// buffer buffer_wrap buffer_; /// use to check whether the user call stop in the listener std::atomic state_ = state_t::stopped; /// use this to ensure that server stop only after all sessions are closed std::shared_ptr counter_ptr_; /// Remote call (rpc/rdc) response timeout. std::chrono::steady_clock::duration rc_timeout_ = std::chrono::milliseconds(http_execute_timeout); /// the pointer of ecs_t std::shared_ptr ecs_; /// Whether the async_read... is called. bool reading_ = false; #if defined(_DEBUG) || defined(DEBUG) std::atomic post_send_counter_ = 0; std::atomic post_recv_counter_ = 0; #endif }; } #include #endif // !__ASIO2_SESSION_HPP__