]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/asio/include/boost/asio/ssl/old/detail/openssl_stream_service.hpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / libs / asio / include / boost / asio / ssl / old / detail / openssl_stream_service.hpp
1 //
2 // ssl/old/detail/stream_service.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
6 // Copyright (c) 2005-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
7 //
8 // Distributed under the Boost Software License, Version 1.0. (See accompanying
9 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
10 //
11
12 #ifndef BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_STREAM_SERVICE_HPP
13 #define BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_STREAM_SERVICE_HPP
14
15 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
16 # pragma once
17 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
18
19 #include <boost/asio/detail/config.hpp>
20 #include <cstddef>
21 #include <climits>
22 #include <memory>
23 #include <boost/config.hpp>
24 #include <boost/noncopyable.hpp>
25 #include <boost/function.hpp>
26 #include <boost/bind.hpp>
27 #include <boost/asio/detail/buffer_sequence_adapter.hpp>
28 #include <boost/asio/error.hpp>
29 #include <boost/asio/io_service.hpp>
30 #include <boost/asio/ssl/basic_context.hpp>
31 #include <boost/asio/ssl/stream_base.hpp>
32 #include <boost/asio/ssl/old/detail/openssl_operation.hpp>
33 #include <boost/asio/ssl/detail/openssl_types.hpp>
34 #include <boost/asio/strand.hpp>
35 #include <boost/system/system_error.hpp>
36
37 #include <boost/asio/detail/push_options.hpp>
38
39 namespace boost {
40 namespace asio {
41 namespace ssl {
42 namespace old {
43 namespace detail {
44
45 class openssl_stream_service
46 : public boost::asio::detail::service_base<openssl_stream_service>
47 {
48 private:
49 enum { max_buffer_size = INT_MAX };
50
51 //Base handler for asyncrhonous operations
52 template <typename Stream>
53 class base_handler
54 {
55 public:
56 typedef boost::function<
57 void (const boost::system::error_code&, size_t)> func_t;
58
59 base_handler(boost::asio::io_service& io_service)
60 : op_(NULL)
61 , io_service_(io_service)
62 , work_(io_service)
63 {}
64
65 void do_func(const boost::system::error_code& error, size_t size)
66 {
67 func_(error, size);
68 }
69
70 void set_operation(openssl_operation<Stream>* op) { op_ = op; }
71 void set_func(func_t func) { func_ = func; }
72
73 ~base_handler()
74 {
75 delete op_;
76 }
77
78 private:
79 func_t func_;
80 openssl_operation<Stream>* op_;
81 boost::asio::io_service& io_service_;
82 boost::asio::io_service::work work_;
83 }; // class base_handler
84
85 // Handler for asynchronous IO (write/read) operations
86 template<typename Stream, typename Handler>
87 class io_handler
88 : public base_handler<Stream>
89 {
90 public:
91 io_handler(Handler handler, boost::asio::io_service& io_service)
92 : base_handler<Stream>(io_service)
93 , handler_(handler)
94 {
95 this->set_func(boost::bind(
96 &io_handler<Stream, Handler>::handler_impl,
97 this, boost::arg<1>(), boost::arg<2>() ));
98 }
99
100 private:
101 Handler handler_;
102 void handler_impl(const boost::system::error_code& error, size_t size)
103 {
104 std::auto_ptr<io_handler<Stream, Handler> > this_ptr(this);
105 handler_(error, size);
106 }
107 }; // class io_handler
108
109 // Handler for asyncrhonous handshake (connect, accept) functions
110 template <typename Stream, typename Handler>
111 class handshake_handler
112 : public base_handler<Stream>
113 {
114 public:
115 handshake_handler(Handler handler, boost::asio::io_service& io_service)
116 : base_handler<Stream>(io_service)
117 , handler_(handler)
118 {
119 this->set_func(boost::bind(
120 &handshake_handler<Stream, Handler>::handler_impl,
121 this, boost::arg<1>(), boost::arg<2>() ));
122 }
123
124 private:
125 Handler handler_;
126 void handler_impl(const boost::system::error_code& error, size_t)
127 {
128 std::auto_ptr<handshake_handler<Stream, Handler> > this_ptr(this);
129 handler_(error);
130 }
131
132 }; // class handshake_handler
133
134 // Handler for asyncrhonous shutdown
135 template <typename Stream, typename Handler>
136 class shutdown_handler
137 : public base_handler<Stream>
138 {
139 public:
140 shutdown_handler(Handler handler, boost::asio::io_service& io_service)
141 : base_handler<Stream>(io_service),
142 handler_(handler)
143 {
144 this->set_func(boost::bind(
145 &shutdown_handler<Stream, Handler>::handler_impl,
146 this, boost::arg<1>(), boost::arg<2>() ));
147 }
148
149 private:
150 Handler handler_;
151 void handler_impl(const boost::system::error_code& error, size_t)
152 {
153 std::auto_ptr<shutdown_handler<Stream, Handler> > this_ptr(this);
154 handler_(error);
155 }
156 }; // class shutdown_handler
157
158 public:
159 // The implementation type.
160 typedef struct impl_struct
161 {
162 ::SSL* ssl;
163 ::BIO* ext_bio;
164 net_buffer recv_buf;
165 } * impl_type;
166
167 // Construct a new stream socket service for the specified io_service.
168 explicit openssl_stream_service(boost::asio::io_service& io_service)
169 : boost::asio::detail::service_base<openssl_stream_service>(io_service),
170 strand_(io_service)
171 {
172 }
173
174 // Destroy all user-defined handler objects owned by the service.
175 void shutdown_service()
176 {
177 }
178
179 // Return a null stream implementation.
180 impl_type null() const
181 {
182 return 0;
183 }
184
185 // Create a new stream implementation.
186 template <typename Stream, typename Context_Service>
187 void create(impl_type& impl, Stream& /*next_layer*/,
188 basic_context<Context_Service>& context)
189 {
190 impl = new impl_struct;
191 impl->ssl = ::SSL_new(context.impl());
192 ::SSL_set_mode(impl->ssl, SSL_MODE_ENABLE_PARTIAL_WRITE);
193 ::SSL_set_mode(impl->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
194 ::BIO* int_bio = 0;
195 impl->ext_bio = 0;
196 ::BIO_new_bio_pair(&int_bio, 8192, &impl->ext_bio, 8192);
197 ::SSL_set_bio(impl->ssl, int_bio, int_bio);
198 }
199
200 // Destroy a stream implementation.
201 template <typename Stream>
202 void destroy(impl_type& impl, Stream& /*next_layer*/)
203 {
204 if (impl != 0)
205 {
206 ::BIO_free(impl->ext_bio);
207 ::SSL_free(impl->ssl);
208 delete impl;
209 impl = 0;
210 }
211 }
212
213 // Perform SSL handshaking.
214 template <typename Stream>
215 boost::system::error_code handshake(impl_type& impl, Stream& next_layer,
216 stream_base::handshake_type type, boost::system::error_code& ec)
217 {
218 try
219 {
220 openssl_operation<Stream> op(
221 type == stream_base::client ?
222 &ssl_wrap<mutex_type>::SSL_connect:
223 &ssl_wrap<mutex_type>::SSL_accept,
224 next_layer,
225 impl->recv_buf,
226 impl->ssl,
227 impl->ext_bio);
228 op.start();
229 }
230 catch (boost::system::system_error& e)
231 {
232 ec = e.code();
233 return ec;
234 }
235
236 ec = boost::system::error_code();
237 return ec;
238 }
239
240 // Start an asynchronous SSL handshake.
241 template <typename Stream, typename Handler>
242 void async_handshake(impl_type& impl, Stream& next_layer,
243 stream_base::handshake_type type, Handler handler)
244 {
245 typedef handshake_handler<Stream, Handler> connect_handler;
246
247 connect_handler* local_handler =
248 new connect_handler(handler, get_io_service());
249
250 openssl_operation<Stream>* op = new openssl_operation<Stream>
251 (
252 type == stream_base::client ?
253 &ssl_wrap<mutex_type>::SSL_connect:
254 &ssl_wrap<mutex_type>::SSL_accept,
255 next_layer,
256 impl->recv_buf,
257 impl->ssl,
258 impl->ext_bio,
259 boost::bind
260 (
261 &base_handler<Stream>::do_func,
262 local_handler,
263 boost::arg<1>(),
264 boost::arg<2>()
265 ),
266 strand_
267 );
268 local_handler->set_operation(op);
269
270 strand_.post(boost::bind(&openssl_operation<Stream>::start, op));
271 }
272
273 // Shut down SSL on the stream.
274 template <typename Stream>
275 boost::system::error_code shutdown(impl_type& impl, Stream& next_layer,
276 boost::system::error_code& ec)
277 {
278 try
279 {
280 openssl_operation<Stream> op(
281 &ssl_wrap<mutex_type>::SSL_shutdown,
282 next_layer,
283 impl->recv_buf,
284 impl->ssl,
285 impl->ext_bio);
286 op.start();
287 }
288 catch (boost::system::system_error& e)
289 {
290 ec = e.code();
291 return ec;
292 }
293
294 ec = boost::system::error_code();
295 return ec;
296 }
297
298 // Asynchronously shut down SSL on the stream.
299 template <typename Stream, typename Handler>
300 void async_shutdown(impl_type& impl, Stream& next_layer, Handler handler)
301 {
302 typedef shutdown_handler<Stream, Handler> disconnect_handler;
303
304 disconnect_handler* local_handler =
305 new disconnect_handler(handler, get_io_service());
306
307 openssl_operation<Stream>* op = new openssl_operation<Stream>
308 (
309 &ssl_wrap<mutex_type>::SSL_shutdown,
310 next_layer,
311 impl->recv_buf,
312 impl->ssl,
313 impl->ext_bio,
314 boost::bind
315 (
316 &base_handler<Stream>::do_func,
317 local_handler,
318 boost::arg<1>(),
319 boost::arg<2>()
320 ),
321 strand_
322 );
323 local_handler->set_operation(op);
324
325 strand_.post(boost::bind(&openssl_operation<Stream>::start, op));
326 }
327
328 // Write some data to the stream.
329 template <typename Stream, typename Const_Buffers>
330 std::size_t write_some(impl_type& impl, Stream& next_layer,
331 const Const_Buffers& buffers, boost::system::error_code& ec)
332 {
333 size_t bytes_transferred = 0;
334 try
335 {
336 boost::asio::const_buffer buffer =
337 boost::asio::detail::buffer_sequence_adapter<
338 boost::asio::const_buffer, Const_Buffers>::first(buffers);
339
340 std::size_t buffer_size = boost::asio::buffer_size(buffer);
341 if (buffer_size > max_buffer_size)
342 buffer_size = max_buffer_size;
343 else if (buffer_size == 0)
344 {
345 ec = boost::system::error_code();
346 return 0;
347 }
348
349 boost::function<int (SSL*)> send_func =
350 boost::bind(boost::type<int>(), &::SSL_write, boost::arg<1>(),
351 boost::asio::buffer_cast<const void*>(buffer),
352 static_cast<int>(buffer_size));
353 openssl_operation<Stream> op(
354 send_func,
355 next_layer,
356 impl->recv_buf,
357 impl->ssl,
358 impl->ext_bio
359 );
360 bytes_transferred = static_cast<size_t>(op.start());
361 }
362 catch (boost::system::system_error& e)
363 {
364 ec = e.code();
365 return 0;
366 }
367
368 ec = boost::system::error_code();
369 return bytes_transferred;
370 }
371
372 // Start an asynchronous write.
373 template <typename Stream, typename Const_Buffers, typename Handler>
374 void async_write_some(impl_type& impl, Stream& next_layer,
375 const Const_Buffers& buffers, Handler handler)
376 {
377 typedef io_handler<Stream, Handler> send_handler;
378
379 boost::asio::const_buffer buffer =
380 boost::asio::detail::buffer_sequence_adapter<
381 boost::asio::const_buffer, Const_Buffers>::first(buffers);
382
383 std::size_t buffer_size = boost::asio::buffer_size(buffer);
384 if (buffer_size > max_buffer_size)
385 buffer_size = max_buffer_size;
386 else if (buffer_size == 0)
387 {
388 get_io_service().post(boost::asio::detail::bind_handler(
389 handler, boost::system::error_code(), 0));
390 return;
391 }
392
393 send_handler* local_handler = new send_handler(handler, get_io_service());
394
395 boost::function<int (SSL*)> send_func =
396 boost::bind(boost::type<int>(), &::SSL_write, boost::arg<1>(),
397 boost::asio::buffer_cast<const void*>(buffer),
398 static_cast<int>(buffer_size));
399
400 openssl_operation<Stream>* op = new openssl_operation<Stream>
401 (
402 send_func,
403 next_layer,
404 impl->recv_buf,
405 impl->ssl,
406 impl->ext_bio,
407 boost::bind
408 (
409 &base_handler<Stream>::do_func,
410 local_handler,
411 boost::arg<1>(),
412 boost::arg<2>()
413 ),
414 strand_
415 );
416 local_handler->set_operation(op);
417
418 strand_.post(boost::bind(&openssl_operation<Stream>::start, op));
419 }
420
421 // Read some data from the stream.
422 template <typename Stream, typename Mutable_Buffers>
423 std::size_t read_some(impl_type& impl, Stream& next_layer,
424 const Mutable_Buffers& buffers, boost::system::error_code& ec)
425 {
426 size_t bytes_transferred = 0;
427 try
428 {
429 boost::asio::mutable_buffer buffer =
430 boost::asio::detail::buffer_sequence_adapter<
431 boost::asio::mutable_buffer, Mutable_Buffers>::first(buffers);
432
433 std::size_t buffer_size = boost::asio::buffer_size(buffer);
434 if (buffer_size > max_buffer_size)
435 buffer_size = max_buffer_size;
436 else if (buffer_size == 0)
437 {
438 ec = boost::system::error_code();
439 return 0;
440 }
441
442 boost::function<int (SSL*)> recv_func =
443 boost::bind(boost::type<int>(), &::SSL_read, boost::arg<1>(),
444 boost::asio::buffer_cast<void*>(buffer),
445 static_cast<int>(buffer_size));
446 openssl_operation<Stream> op(recv_func,
447 next_layer,
448 impl->recv_buf,
449 impl->ssl,
450 impl->ext_bio
451 );
452
453 bytes_transferred = static_cast<size_t>(op.start());
454 }
455 catch (boost::system::system_error& e)
456 {
457 ec = e.code();
458 return 0;
459 }
460
461 ec = boost::system::error_code();
462 return bytes_transferred;
463 }
464
465 // Start an asynchronous read.
466 template <typename Stream, typename Mutable_Buffers, typename Handler>
467 void async_read_some(impl_type& impl, Stream& next_layer,
468 const Mutable_Buffers& buffers, Handler handler)
469 {
470 typedef io_handler<Stream, Handler> recv_handler;
471
472 boost::asio::mutable_buffer buffer =
473 boost::asio::detail::buffer_sequence_adapter<
474 boost::asio::mutable_buffer, Mutable_Buffers>::first(buffers);
475
476 std::size_t buffer_size = boost::asio::buffer_size(buffer);
477 if (buffer_size > max_buffer_size)
478 buffer_size = max_buffer_size;
479 else if (buffer_size == 0)
480 {
481 get_io_service().post(boost::asio::detail::bind_handler(
482 handler, boost::system::error_code(), 0));
483 return;
484 }
485
486 recv_handler* local_handler = new recv_handler(handler, get_io_service());
487
488 boost::function<int (SSL*)> recv_func =
489 boost::bind(boost::type<int>(), &::SSL_read, boost::arg<1>(),
490 boost::asio::buffer_cast<void*>(buffer),
491 static_cast<int>(buffer_size));
492
493 openssl_operation<Stream>* op = new openssl_operation<Stream>
494 (
495 recv_func,
496 next_layer,
497 impl->recv_buf,
498 impl->ssl,
499 impl->ext_bio,
500 boost::bind
501 (
502 &base_handler<Stream>::do_func,
503 local_handler,
504 boost::arg<1>(),
505 boost::arg<2>()
506 ),
507 strand_
508 );
509 local_handler->set_operation(op);
510
511 strand_.post(boost::bind(&openssl_operation<Stream>::start, op));
512 }
513
514 // Peek at the incoming data on the stream.
515 template <typename Stream, typename Mutable_Buffers>
516 std::size_t peek(impl_type& /*impl*/, Stream& /*next_layer*/,
517 const Mutable_Buffers& /*buffers*/, boost::system::error_code& ec)
518 {
519 ec = boost::system::error_code();
520 return 0;
521 }
522
523 // Determine the amount of data that may be read without blocking.
524 template <typename Stream>
525 std::size_t in_avail(impl_type& /*impl*/, Stream& /*next_layer*/,
526 boost::system::error_code& ec)
527 {
528 ec = boost::system::error_code();
529 return 0;
530 }
531
532 private:
533 boost::asio::io_service::strand strand_;
534
535 typedef boost::asio::detail::mutex mutex_type;
536
537 template<typename Mutex>
538 struct ssl_wrap
539 {
540 static Mutex ssl_mutex_;
541
542 static int SSL_accept(SSL *ssl)
543 {
544 typename Mutex::scoped_lock lock(ssl_mutex_);
545 return ::SSL_accept(ssl);
546 }
547
548 static int SSL_connect(SSL *ssl)
549 {
550 typename Mutex::scoped_lock lock(ssl_mutex_);
551 return ::SSL_connect(ssl);
552 }
553
554 static int SSL_shutdown(SSL *ssl)
555 {
556 typename Mutex::scoped_lock lock(ssl_mutex_);
557 return ::SSL_shutdown(ssl);
558 }
559 };
560 };
561
562 template<typename Mutex>
563 Mutex openssl_stream_service::ssl_wrap<Mutex>::ssl_mutex_;
564
565 } // namespace detail
566 } // namespace old
567 } // namespace ssl
568 } // namespace asio
569 } // namespace boost
570
571 #include <boost/asio/detail/pop_options.hpp>
572
573 #endif // BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_STREAM_SERVICE_HPP