OSDN Git Service

Modify ssl shutdown.(Add async shutdown)
[ultramonkey-l7/ultramonkey-l7-v3.git] / l7vsd / include / tcp_ssl_socket.h
index b259d73..64de5a4 100644 (file)
 #ifndef TCP_SSL_SOCKET_H
 #define TCP_SSL_SOCKET_H
 
-#include <bitset>
-#include <boost/asio.hpp>
 #include <boost/asio/ssl.hpp>
-#include <boost/thread/mutex.hpp>
-
-#include "tcp_socket_option.h"
-#include "wrlock.h"
-#include "utility.h"
-#include "logger.h"
-
-typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket>  ssl_socket;
+#include "basic_tcp_socket.h"
 
 namespace l7vs
 {
 
-//! @class    tcp_ssl_socket
-//! @brief    this class is tcp session object use socket.
-class tcp_ssl_socket : private boost::noncopyable
+typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket>  ssl_socket;
+
+class   tcp_ssl_socket : public basic_tcp_socket< ssl_socket >
 {
 public:
-        //! construcor
-        //! @param[in/out]    socket use io service object
-        //! @param[in]        set socket option info
-        tcp_ssl_socket(boost::asio::io_service &io,
-                       boost::asio::ssl::context &context,
-                       const tcp_socket_option_info set_option)
-                :
-                my_io(io),
-                my_context(context),
-                my_socket(NULL),
-                open_flag(false),
-                non_blocking_flag(false),
-                opt_info(set_option),
-                handshake_error_flag(false) {
-                if (unlikely(LOG_LV_DEBUG == Logger::getLogLevel(
-                                     LOG_CAT_L7VSD_SESSION))) {
-                        Logger::putLogDebug(LOG_CAT_L7VSD_SESSION, 1,
-                                            "tcp_ssl_socket::tcp_ssl_socket", __FILE__, __LINE__);
+        // typedef
+        typedef boost::function< void (const boost::system::error_code &) > async_handshake_handler_t;
+        typedef boost::function< void (const boost::system::error_code &) > async_shutdown_handler_t;
+
+        // constructor
+        tcp_ssl_socket(
+                boost::asio::io_service        &io_service,
+                const tcp_socket_option_info set_option,
+                boost::asio::ssl::context      &context)
+                :       basic_tcp_socket< ssl_socket >(io_service, set_option),
+                        context_(context),
+                        ssl_strand(io_service),
+                        handshake_con(0),
+                        read_con(0),
+                        write_con(0) {
+                my_socket.reset(new ssl_socket(io_service_, context_));
+        }
+        //destructor
+        ~tcp_ssl_socket() {}
+
+        // handshake
+        virtual bool handshake(boost::system::error_code &error_code) {
+                boost::mutex::scoped_lock       lock(ssl_mutex);
+                my_socket->handshake(boost::asio::ssl::stream_base::server, error_code);
+                return error_code ? false : true;
+        }
+        //async handshake
+        virtual void async_handshake(async_handshake_handler_t  handler) {
+                boost::mutex::scoped_lock       lock(ssl_mutex);
+                handshake_con++;
+                my_socket->async_handshake(boost::asio::ssl::stream_base::server, ssl_strand.wrap(handler));
+        }
+
+        // option setting
+        virtual void setoption(boost::system::error_code &error_code) {
+                // non blocking mode
+                boost::asio::socket_base::non_blocking_io       cmd(true);
+                my_socket->lowest_layer().io_control(cmd, error_code);
+                if (unlikely(error_code)) {
+                        boost::format   fmt("Thread ID[%d] socket option(NON_BLOCKING_MODE) set fail : %s");
+                        fmt % boost::this_thread::get_id() % error_code.message();
+                        Logger::putLogError(LOG_CAT_L7VSD_SESSION, 100, fmt.str(), __FILE__, __LINE__);
                 }
-                my_socket = new ssl_socket(io, my_context);
-        }
-        //! destructor
-        ~tcp_ssl_socket() {
-                if (unlikely(LOG_LV_DEBUG == Logger::getLogLevel(
-                                     LOG_CAT_L7VSD_SESSION))) {
-                        Logger::putLogDebug(LOG_CAT_L7VSD_SESSION, 2,
-                                            "tcp_ssl_socket::~tcp_ssl_socket", __FILE__, __LINE__);
+                // set TCP_NODELAY option
+                if (opt_info.nodelay_opt) {
+                        boost::asio::ip::tcp::no_delay cmd(opt_info.nodelay_val);
+                        my_socket->lowest_layer().set_option(cmd, error_code);
+                        if (unlikely(error_code)) {
+                                boost::format   fmt("Thread ID[%d] socket option(TCP_NODELAY) set failed");
+                                fmt % boost::this_thread::get_id();
+                                Logger::putLogError(LOG_CAT_L7VSD_SESSION, 100, fmt.str(), __FILE__, __LINE__);
+                        }
                 }
-                if (my_socket != NULL) {
-                        delete my_socket;
-                        my_socket = NULL;
+                // set TCP_CORK
+                if (opt_info.cork_opt) {
+                        int     val = opt_info.cork_val;
+                        int err = ::setsockopt(my_socket->lowest_layer().native(), IPPROTO_TCP, TCP_CORK, &val, sizeof(int));
+                        if (unlikely(err)) {
+                                error_code = boost::system::error_code(errno, boost::asio::error::get_system_category());
+                                boost::format   fmt("Thread ID[%d] socket option(TCP_CORK) set failed");
+                                fmt % boost::this_thread::get_id();
+                                Logger::putLogError(LOG_CAT_L7VSD_SESSION, 101, fmt.str(), __FILE__, __LINE__);
+                        }
                 }
+        }
 
+        // close
+        virtual bool close(boost::system::error_code   &error_code) {
+                boost::mutex::scoped_lock       lock(ssl_mutex);
+                if (my_socket->lowest_layer().is_open()) {
+                        my_socket->lowest_layer().cancel(error_code);
+                        my_socket->lowest_layer().close(error_code);
+                        if (error_code) {
+                                boost::format   fmt("Thread ID[%d] ssl_socket lowest_layer close fail: %s");
+                                fmt % boost::this_thread::get_id() % error_code.message();
+                                Logger::putLogError(LOG_CAT_L7VSD_SESSION, 102, fmt.str(), __FILE__, __LINE__);
+                        }
+                }
+                return error_code ? false : true;
         }
 
-        //! get reference control socket
-        //! @return           reference control socket
-        ssl_socket &get_socket() {
-                if (unlikely(LOG_LV_DEBUG == Logger::getLogLevel(LOG_CAT_L7VSD_SESSION))) {
-                        Logger::putLogDebug(LOG_CAT_L7VSD_SESSION, 3, "tcp_ssl_socket::get_socket", __FILE__, __LINE__);
+
+        virtual bool shutdown(boost::system::error_code &error_code) {
+                boost::mutex::scoped_lock        lock(ssl_mutex);
+                my_socket->lowest_layer().cancel(error_code);
+                my_socket->shutdown(error_code);
+                return error_code ? false : true;
+        }
+
+        virtual void async_shutdown(async_handshake_handler_t  handler) {
+                boost::mutex::scoped_lock       lock(ssl_mutex);
+                boost::system::error_code       error_code;
+                shutdown_con++;
+                my_socket->lowest_layer().cancel(error_code);
+                my_socket->async_shutdown(ssl_strand.wrap(handler));
+        }
+
+        virtual std::size_t     read_some(const boost::asio::mutable_buffers_1 &buffers, boost::system::error_code &error_code) {
+                boost::mutex::scoped_lock       lock(ssl_mutex);
+                if (write_con > 0 || handshake_con > 0) {
+                        error_code = boost::asio::error::try_again;
+                        return 0;
                 }
-                return *my_socket;
+                if (opt_info.quickack_opt) set_quickack(error_code);
+                return my_socket->read_some(buffers, error_code);
+        }
+
+        virtual void    async_read_some(const boost::asio::mutable_buffers_1 &buffer, async_rw_handler_t &handle) {
+                boost::mutex::scoped_lock       lock(ssl_mutex);
+                boost::system::error_code       error_code;
+                read_con++;
+                if (opt_info.quickack_opt) set_quickack(error_code);
+                my_socket->async_read_some(buffer, ssl_strand.wrap(handle));
         }
 
-        //! handshake socket
-        //! @param[in]        handshake_type is handshaking as a server or client
-        bool handshake(boost::system::error_code &ec);
-        //! accept
-        void accept();
-        //! close socket
-        //! @param[out]       ec is reference error code object
-        //! @return           true is socket close
-        //! @return           false is not open socket
-        bool close(boost::system::error_code &ec);
-        //! set non blocking mode of the socket
-        //! @param[out]       ec is reference error code object
-        //! @return           true is set non blocking mode
-        //! @return           false is set non blocking mode failure
-        bool set_non_blocking_mode(boost::system::error_code &ec);
-        //! write socket
-        //! @param[in]        buffers is wite data buffer
-        //! @param[out]       ec is reference error code object
-        //! @return           write data size
-        std::size_t write_some(boost::asio::mutable_buffers_1 buffers, boost::system::error_code &ec);
-        //! read socket
-        //! @param[out]       buffers is read data buffer
-        //! @param[out]       ec is reference error code object
-        //! @return           read data size
-        std::size_t read_some(boost::asio::mutable_buffers_1 buffers, boost::system::error_code &ec);
-        //! is open
-        //! @return           true is open
-        //! @return           false is close
-        bool is_open() {
-                return open_flag;
-        }
-        //! socket remake
-        void clear_socket() {
-                if (my_socket != NULL) {
-                        delete my_socket;
-                        my_socket = NULL;
+        virtual size_t   write_some(const boost::asio::const_buffers_1 &buffer, boost::system::error_code &error_code) {
+                boost::mutex::scoped_lock       lock(ssl_mutex);
+
+                if (read_con > 0 || handshake_con > 0) {
+                        error_code = boost::asio::error::try_again;
+                        return 0;
                 }
-                my_socket = new ssl_socket(my_io, my_context);
-                handshake_error_flag = false;
+                return my_socket->write_some(buffer, error_code);
+        }
+
+        virtual void    async_write_some(const boost::asio::const_buffers_1 &buffer, tcp_socket::async_rw_handler_t &handle) {
+                boost::mutex::scoped_lock       lock(ssl_mutex);
+                write_con++;
+                my_socket->async_write_some(buffer, ssl_strand.wrap(handle));
         }
-        //! is handshake error
-        bool is_handshake_error() {
-                return handshake_error_flag;
+
+        // socket remake
+        virtual void clear_socket() {
+                boost::mutex::scoped_lock       lock(ssl_mutex);
+                my_socket.reset(new ssl_socket(io_service_, context_));
+
+        }
+
+        // get socket
+        virtual ssl_socket &get_socket() {
+                return *my_socket;
+        }
+        virtual bool is_open() {
+                return my_socket->lowest_layer().is_open();
+        }
+
+        void decrement_handshake_con() {
+                boost::mutex::scoped_lock       lock(ssl_mutex);
+                handshake_con--;
+                ssl_cond.notify_one();
+        }
+
+        int get_handshake_con() {
+                return handshake_con;
+        }
+
+        void decrement_read_con() {
+                boost::mutex::scoped_lock       lock(ssl_mutex);
+                read_con--;
+                ssl_cond.notify_one();
+        }
+
+        int get_read_con() {
+                return read_con;
+        }
+
+        void decrement_write_con() {
+                boost::mutex::scoped_lock       lock(ssl_mutex);
+                write_con--;
+                ssl_cond.notify_one();
+        }
+
+        int get_write_con() {
+                return write_con;
+        }
+
+        void decrement_shutdown_con() {
+                boost::mutex::scoped_lock       lock(ssl_mutex);
+                shutdown_con--;
+                ssl_cond.notify_one();
+        }
+
+        int get_shutdown_con() {
+                return shutdown_con;
+        }
+
+        void wait_async_event_all_end() {
+                boost::mutex::scoped_lock       lock(ssl_mutex);
+                while (handshake_con > 0 || read_con > 0 || write_con > 0 || shutdown_con > 0) {
+                        boost::format   fmt("handshake_con : %d read_con = %d write_con = %d ");
+                        fmt % handshake_con % read_con % write_con ;
+                        Logger::putLogInfo(LOG_CAT_L7VSD_SESSION, 999, fmt.str(), __FILE__, __LINE__);
+
+                        ssl_cond.wait(lock);
+                }
         }
 
 protected:
-        //! io service object
-        boost::asio::io_service &my_io;
-        //! SSL context object
-        boost::asio::ssl::context &my_context;
-        //! control socket
-        ssl_socket *my_socket;
-        //! socket close mutex
-        wr_mutex close_mutex;
-        //! socket open flag
-        bool open_flag;
-        //! set nonblocking flag
-        bool non_blocking_flag;
-        //! socket option
-        tcp_socket_option_info opt_info;
-        //! handshake error flag
-        bool handshake_error_flag;
-
-};// class tcp_ssl_socket
-}// namespace l7vs
-
-#endif//TCP_SSL_SOCKET_H
+        //! ssl context reference
+        boost::asio::ssl::context      &context_;
+        //! ssl mutex
+        boost::mutex                            ssl_mutex;
+        boost::condition                        ssl_cond;
+        boost::asio::strand                     ssl_strand;
+        //! set quick ack
+        int handshake_con;
+        int read_con;
+        int write_con;
+        int shutdown_con;
+
+        virtual void set_quickack(boost::system::error_code &error_code) {
+                int err = ::setsockopt(my_socket->lowest_layer().native(), IPPROTO_TCP, TCP_QUICKACK, &opt_info.quickack_val, sizeof(opt_info.quickack_val));
+                if (err) error_code = boost::system::error_code(errno, boost::asio::error::get_system_category());
+        }
+
+};      //class tcp_ssl_socket
 
+}       //namespace l7vs
+#endif  //TCP_SSL_SOCKET_H