#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