2 * @file tcp_ssl_socket.h
3 * @brief tcp ssl session socket class
5 * L7VSD: Linux Virtual Server for Layer7 Load Balancing
6 * Copyright (C) 2009 NTT COMWARE Corporation.
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23 **********************************************************************/
25 #ifndef TCP_SSL_SOCKET_H
26 #define TCP_SSL_SOCKET_H
28 #include <boost/asio/ssl.hpp>
29 #include "basic_tcp_socket.h"
34 typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_socket;
36 class tcp_ssl_socket : public basic_tcp_socket< ssl_socket >
40 typedef boost::function< void (const boost::system::error_code &) > async_handshake_handler_t;
41 typedef boost::function< void (const boost::system::error_code &) > async_shutdown_handler_t;
45 boost::asio::io_service &io_service,
46 const tcp_socket_option_info set_option,
47 boost::asio::ssl::context &context)
48 : basic_tcp_socket< ssl_socket >(io_service, set_option),
50 ssl_strand(io_service),
54 my_socket.reset(new ssl_socket(io_service_, context_));
60 virtual bool handshake(boost::system::error_code &error_code) {
61 boost::mutex::scoped_lock lock(ssl_mutex);
62 my_socket->handshake(boost::asio::ssl::stream_base::server, error_code);
63 return error_code ? false : true;
66 virtual void async_handshake(async_handshake_handler_t handler) {
67 boost::mutex::scoped_lock lock(ssl_mutex);
69 my_socket->async_handshake(boost::asio::ssl::stream_base::server, ssl_strand.wrap(handler));
73 virtual void setoption(boost::system::error_code &error_code) {
75 boost::asio::socket_base::non_blocking_io cmd(true);
76 my_socket->lowest_layer().io_control(cmd, error_code);
77 if (unlikely(error_code)) {
78 boost::format fmt("Thread ID[%d] socket option(NON_BLOCKING_MODE) set fail : %s");
79 fmt % boost::this_thread::get_id() % error_code.message();
80 Logger::putLogError(LOG_CAT_L7VSD_SESSION, 100, fmt.str(), __FILE__, __LINE__);
82 // set TCP_NODELAY option
83 if (opt_info.nodelay_opt) {
84 boost::asio::ip::tcp::no_delay cmd(opt_info.nodelay_val);
85 my_socket->lowest_layer().set_option(cmd, error_code);
86 if (unlikely(error_code)) {
87 boost::format fmt("Thread ID[%d] socket option(TCP_NODELAY) set failed");
88 fmt % boost::this_thread::get_id();
89 Logger::putLogError(LOG_CAT_L7VSD_SESSION, 100, fmt.str(), __FILE__, __LINE__);
93 if (opt_info.cork_opt) {
94 int val = opt_info.cork_val;
95 int err = ::setsockopt(my_socket->lowest_layer().native(), IPPROTO_TCP, TCP_CORK, &val, sizeof(int));
97 error_code = boost::system::error_code(errno, boost::asio::error::get_system_category());
98 boost::format fmt("Thread ID[%d] socket option(TCP_CORK) set failed");
99 fmt % boost::this_thread::get_id();
100 Logger::putLogError(LOG_CAT_L7VSD_SESSION, 101, fmt.str(), __FILE__, __LINE__);
106 virtual bool close(boost::system::error_code &error_code) {
107 boost::mutex::scoped_lock lock(ssl_mutex);
108 if (my_socket->lowest_layer().is_open()) {
109 my_socket->lowest_layer().cancel(error_code);
110 my_socket->lowest_layer().close(error_code);
112 boost::format fmt("Thread ID[%d] ssl_socket lowest_layer close fail: %s");
113 fmt % boost::this_thread::get_id() % error_code.message();
114 Logger::putLogError(LOG_CAT_L7VSD_SESSION, 102, fmt.str(), __FILE__, __LINE__);
117 return error_code ? false : true;
121 virtual bool shutdown(boost::system::error_code &error_code) {
122 boost::mutex::scoped_lock lock(ssl_mutex);
123 my_socket->lowest_layer().cancel(error_code);
124 my_socket->shutdown(error_code);
125 return error_code ? false : true;
128 virtual void async_shutdown(async_handshake_handler_t handler) {
129 boost::mutex::scoped_lock lock(ssl_mutex);
130 boost::system::error_code error_code;
132 my_socket->lowest_layer().cancel(error_code);
133 my_socket->async_shutdown(ssl_strand.wrap(handler));
136 virtual std::size_t read_some(const boost::asio::mutable_buffers_1 &buffers, boost::system::error_code &error_code) {
137 boost::mutex::scoped_lock lock(ssl_mutex);
138 if (write_con > 0 || handshake_con > 0) {
139 error_code = boost::asio::error::try_again;
142 if (opt_info.quickack_opt) set_quickack(error_code);
143 return my_socket->read_some(buffers, error_code);
146 virtual void async_read_some(const boost::asio::mutable_buffers_1 &buffer, async_rw_handler_t &handle) {
147 boost::mutex::scoped_lock lock(ssl_mutex);
148 boost::system::error_code error_code;
150 if (opt_info.quickack_opt) set_quickack(error_code);
151 my_socket->async_read_some(buffer, ssl_strand.wrap(handle));
154 virtual size_t write_some(const boost::asio::const_buffers_1 &buffer, boost::system::error_code &error_code) {
155 boost::mutex::scoped_lock lock(ssl_mutex);
157 if (read_con > 0 || handshake_con > 0) {
158 error_code = boost::asio::error::try_again;
161 return my_socket->write_some(buffer, error_code);
164 virtual void async_write_some(const boost::asio::const_buffers_1 &buffer, tcp_socket::async_rw_handler_t &handle) {
165 boost::mutex::scoped_lock lock(ssl_mutex);
167 my_socket->async_write_some(buffer, ssl_strand.wrap(handle));
171 virtual void clear_socket() {
172 boost::mutex::scoped_lock lock(ssl_mutex);
173 my_socket.reset(new ssl_socket(io_service_, context_));
178 virtual ssl_socket &get_socket() {
181 virtual bool is_open() {
182 return my_socket->lowest_layer().is_open();
185 void decrement_handshake_con() {
186 boost::mutex::scoped_lock lock(ssl_mutex);
188 ssl_cond.notify_one();
191 int get_handshake_con() {
192 return handshake_con;
195 void decrement_read_con() {
196 boost::mutex::scoped_lock lock(ssl_mutex);
198 ssl_cond.notify_one();
205 void decrement_write_con() {
206 boost::mutex::scoped_lock lock(ssl_mutex);
208 ssl_cond.notify_one();
211 int get_write_con() {
215 void decrement_shutdown_con() {
216 boost::mutex::scoped_lock lock(ssl_mutex);
218 ssl_cond.notify_one();
221 int get_shutdown_con() {
225 void wait_async_event_all_end() {
226 boost::mutex::scoped_lock lock(ssl_mutex);
227 while (handshake_con > 0 || read_con > 0 || write_con > 0 || shutdown_con > 0) {
228 boost::format fmt("handshake_con : %d read_con = %d write_con = %d ");
229 fmt % handshake_con % read_con % write_con ;
230 Logger::putLogInfo(LOG_CAT_L7VSD_SESSION, 999, fmt.str(), __FILE__, __LINE__);
237 //! ssl context reference
238 boost::asio::ssl::context &context_;
240 boost::mutex ssl_mutex;
241 boost::condition ssl_cond;
242 boost::asio::strand ssl_strand;
249 virtual void set_quickack(boost::system::error_code &error_code) {
250 int err = ::setsockopt(my_socket->lowest_layer().native(), IPPROTO_TCP, TCP_QUICKACK, &opt_info.quickack_val, sizeof(opt_info.quickack_val));
251 if (err) error_code = boost::system::error_code(errno, boost::asio::error::get_system_category());
254 }; //class tcp_ssl_socket
257 #endif //TCP_SSL_SOCKET_H