OSDN Git Service

Modify ssl shutdown.(Add async shutdown)
[ultramonkey-l7/ultramonkey-l7-v3.git] / l7vsd / include / tcp_ssl_socket.h
1 /*!
2  *    @file    tcp_ssl_socket.h
3  *    @brief    tcp ssl session socket class
4  *
5  * L7VSD: Linux Virtual Server for Layer7 Load Balancing
6  * Copyright (C) 2009  NTT COMWARE Corporation.
7  *
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.
12  *
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.
17  *
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
21  * 02110-1301 USA
22  *
23  **********************************************************************/
24
25 #ifndef TCP_SSL_SOCKET_H
26 #define TCP_SSL_SOCKET_H
27
28 #include <boost/asio/ssl.hpp>
29 #include "basic_tcp_socket.h"
30
31 namespace l7vs
32 {
33
34 typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket>  ssl_socket;
35
36 class   tcp_ssl_socket : public basic_tcp_socket< ssl_socket >
37 {
38 public:
39         // typedef
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;
42
43         // constructor
44         tcp_ssl_socket(
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),
49                         context_(context),
50                         ssl_strand(io_service),
51                         handshake_con(0),
52                         read_con(0),
53                         write_con(0) {
54                 my_socket.reset(new ssl_socket(io_service_, context_));
55         }
56         //destructor
57         ~tcp_ssl_socket() {}
58
59         // handshake
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;
64         }
65         //async handshake
66         virtual void async_handshake(async_handshake_handler_t  handler) {
67                 boost::mutex::scoped_lock       lock(ssl_mutex);
68                 handshake_con++;
69                 my_socket->async_handshake(boost::asio::ssl::stream_base::server, ssl_strand.wrap(handler));
70         }
71
72         // option setting
73         virtual void setoption(boost::system::error_code &error_code) {
74                 // non blocking mode
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__);
81                 }
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__);
90                         }
91                 }
92                 // set TCP_CORK
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));
96                         if (unlikely(err)) {
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__);
101                         }
102                 }
103         }
104
105         // close
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);
111                         if (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__);
115                         }
116                 }
117                 return error_code ? false : true;
118         }
119
120
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;
126         }
127
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;
131                 shutdown_con++;
132                 my_socket->lowest_layer().cancel(error_code);
133                 my_socket->async_shutdown(ssl_strand.wrap(handler));
134         }
135
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;
140                         return 0;
141                 }
142                 if (opt_info.quickack_opt) set_quickack(error_code);
143                 return my_socket->read_some(buffers, error_code);
144         }
145
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;
149                 read_con++;
150                 if (opt_info.quickack_opt) set_quickack(error_code);
151                 my_socket->async_read_some(buffer, ssl_strand.wrap(handle));
152         }
153
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);
156
157                 if (read_con > 0 || handshake_con > 0) {
158                         error_code = boost::asio::error::try_again;
159                         return 0;
160                 }
161                 return my_socket->write_some(buffer, error_code);
162         }
163
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);
166                 write_con++;
167                 my_socket->async_write_some(buffer, ssl_strand.wrap(handle));
168         }
169
170         // socket remake
171         virtual void clear_socket() {
172                 boost::mutex::scoped_lock       lock(ssl_mutex);
173                 my_socket.reset(new ssl_socket(io_service_, context_));
174
175         }
176
177         // get socket
178         virtual ssl_socket &get_socket() {
179                 return *my_socket;
180         }
181         virtual bool is_open() {
182                 return my_socket->lowest_layer().is_open();
183         }
184
185         void decrement_handshake_con() {
186                 boost::mutex::scoped_lock       lock(ssl_mutex);
187                 handshake_con--;
188                 ssl_cond.notify_one();
189         }
190
191         int get_handshake_con() {
192                 return handshake_con;
193         }
194
195         void decrement_read_con() {
196                 boost::mutex::scoped_lock       lock(ssl_mutex);
197                 read_con--;
198                 ssl_cond.notify_one();
199         }
200
201         int get_read_con() {
202                 return read_con;
203         }
204
205         void decrement_write_con() {
206                 boost::mutex::scoped_lock       lock(ssl_mutex);
207                 write_con--;
208                 ssl_cond.notify_one();
209         }
210
211         int get_write_con() {
212                 return write_con;
213         }
214
215         void decrement_shutdown_con() {
216                 boost::mutex::scoped_lock       lock(ssl_mutex);
217                 shutdown_con--;
218                 ssl_cond.notify_one();
219         }
220
221         int get_shutdown_con() {
222                 return shutdown_con;
223         }
224
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__);
231
232                         ssl_cond.wait(lock);
233                 }
234         }
235
236 protected:
237         //! ssl context reference
238         boost::asio::ssl::context      &context_;
239         //! ssl mutex
240         boost::mutex                            ssl_mutex;
241         boost::condition                        ssl_cond;
242         boost::asio::strand                     ssl_strand;
243         //! set quick ack
244         int handshake_con;
245         int read_con;
246         int write_con;
247         int shutdown_con;
248
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());
252         }
253
254 };      //class tcp_ssl_socket
255
256 }       //namespace l7vs
257 #endif  //TCP_SSL_SOCKET_H