2
// openssl_operation.hpp
3
// ~~~~~~~~~~~~~~~~~~~~~
5
// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
7
// Distributed under the Boost Software License, Version 1.0. (See accompanying
8
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
11
#ifndef ASIO_SSL_DETAIL_OPENSSL_OPERATION_HPP
12
#define ASIO_SSL_DETAIL_OPENSSL_OPERATION_HPP
14
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
16
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
18
#include "asio/detail/push_options.hpp"
20
#include "asio/detail/push_options.hpp"
21
#include <boost/function.hpp>
22
#include <boost/assert.hpp>
23
#include <boost/bind.hpp>
24
#include "asio/detail/pop_options.hpp"
26
#include "asio/buffer.hpp"
27
#include "asio/placeholders.hpp"
28
#include "asio/write.hpp"
29
#include "asio/detail/socket_ops.hpp"
30
#include "asio/ssl/detail/openssl_types.hpp"
36
typedef boost::function<int (::SSL*)> ssl_primitive_func;
37
typedef boost::function<void (const asio::error_code&, int)>
40
// Network send_/recv buffer implementation
45
static const int NET_BUF_SIZE = 16*1024 + 256; // SSL record size + spare
47
unsigned char buf_[NET_BUF_SIZE];
48
unsigned char* data_start_;
49
unsigned char* data_end_;
54
data_start_ = data_end_ = buf_;
56
unsigned char* get_unused_start() { return data_end_; }
57
unsigned char* get_data_start() { return data_start_; }
58
size_t get_unused_len() { return (NET_BUF_SIZE - (data_end_ - buf_)); }
59
size_t get_data_len() { return (data_end_ - data_start_); }
60
void data_added(size_t count)
63
data_end_ = data_end_ > (buf_ + NET_BUF_SIZE)?
64
(buf_ + NET_BUF_SIZE):
67
void data_removed(size_t count)
70
if (data_start_ >= data_end_) reset();
72
void reset() { data_start_ = buf_; data_end_ = buf_; }
73
bool has_data() { return (data_start_ < data_end_); }
74
}; // class net_buffer
80
template <typename Stream>
81
class openssl_operation
85
// Constructor for asynchronous operations
86
openssl_operation(ssl_primitive_func primitive,
91
user_handler_func handler,
92
asio::io_service::strand& strand
94
: primitive_(primitive)
95
, user_handler_(handler)
102
write_ = boost::bind(
103
&openssl_operation::do_async_write,
104
this, boost::arg<1>(), boost::arg<2>()
107
&openssl_operation::do_async_read,
110
handler_= boost::bind(
111
&openssl_operation::async_user_handler,
112
this, boost::arg<1>(), boost::arg<2>()
116
// Constructor for synchronous operations
117
openssl_operation(ssl_primitive_func primitive,
119
net_buffer& recv_buf,
122
: primitive_(primitive)
124
, recv_buf_(recv_buf)
129
write_ = boost::bind(
130
&openssl_operation::do_sync_write,
131
this, boost::arg<1>(), boost::arg<2>()
134
&openssl_operation::do_sync_read,
137
handler_ = boost::bind(
138
&openssl_operation::sync_user_handler,
139
this, boost::arg<1>(), boost::arg<2>()
144
// In case of asynchronous it returns 0, in sync mode returns success code
145
// or throws an error...
148
int rc = primitive_( session_ );
150
bool is_operation_done = (rc > 0);
151
// For connect/accept/shutdown, the operation
152
// is done, when return code is 1
153
// for write, it is done, when is retcode > 0
154
// for read, is is done when retcode > 0
156
int error_code = !is_operation_done ?
157
::SSL_get_error( session_, rc ) :
159
int sys_error_code = ERR_get_error();
161
if (error_code == SSL_ERROR_SSL)
162
return handler_(asio::error_code(
163
error_code, asio::error::get_ssl_category()), rc);
165
bool is_read_needed = (error_code == SSL_ERROR_WANT_READ);
166
bool is_write_needed = (error_code == SSL_ERROR_WANT_WRITE ||
167
::BIO_ctrl_pending( ssl_bio_ ));
168
bool is_shut_down_received =
169
((::SSL_get_shutdown( session_ ) & SSL_RECEIVED_SHUTDOWN) ==
170
SSL_RECEIVED_SHUTDOWN);
171
bool is_shut_down_sent =
172
((::SSL_get_shutdown( session_ ) & SSL_SENT_SHUTDOWN) ==
175
if (is_shut_down_sent && is_shut_down_received && is_operation_done && !is_write_needed)
176
// SSL connection is shut down cleanly
177
return handler_(asio::error_code(), 1);
179
if (is_shut_down_received && !is_operation_done)
180
// Shutdown has been requested, while we were reading or writing...
181
// abort our action...
182
return handler_(asio::error::shut_down, 0);
184
if (!is_operation_done && !is_read_needed && !is_write_needed
185
&& !is_shut_down_sent)
187
// The operation has failed... It is not completed and does
188
// not want network communication nor does want to send shutdown out...
189
if (error_code == SSL_ERROR_SYSCALL)
191
return handler_(asio::error_code(
192
sys_error_code, asio::error::system_category), rc);
196
return handler_(asio::error_code(
197
error_code, asio::error::get_ssl_category()), rc);
201
if (!is_operation_done && !is_write_needed)
203
// We may have left over data that we can pass to SSL immediately
204
if (recv_buf_.get_data_len() > 0)
206
// Pass the buffered data to SSL
207
int written = ::BIO_write
210
recv_buf_.get_data_start(),
211
recv_buf_.get_data_len()
216
recv_buf_.data_removed(written);
218
else if (written < 0)
220
if (!BIO_should_retry(ssl_bio_))
222
// Some serios error with BIO....
223
return handler_(asio::error::no_recovery, 0);
229
else if (is_read_needed || (is_shut_down_sent && !is_shut_down_received))
235
// Continue with operation, flush any SSL data out to network...
236
return write_(is_operation_done, rc);
239
// Private implementation
241
typedef boost::function<int (const asio::error_code&, int)>
243
typedef boost::function<int (bool, int)> write_func;
244
typedef boost::function<int ()> read_func;
246
ssl_primitive_func primitive_;
247
user_handler_func user_handler_;
248
asio::io_service::strand* strand_;
251
int_handler_func handler_;
253
net_buffer send_buf_; // buffers for network IO
255
// The recv buffer is owned by the stream, not the operation, since there can
256
// be left over bytes after passing the data up to the application, and these
257
// bytes need to be kept around for the next read operation issued by the
259
net_buffer& recv_buf_;
266
int sync_user_handler(const asio::error_code& error, int rc)
271
throw asio::system_error(error);
274
int async_user_handler(asio::error_code error, int rc)
279
error = asio::error::no_recovery;
283
user_handler_(error, rc);
287
// Writes bytes asynchronously from SSL to NET
288
int do_async_write(bool is_operation_done, int rc)
290
int len = ::BIO_ctrl_pending( ssl_bio_ );
293
// There is something to write into net, do it...
294
len = (int)send_buf_.get_unused_len() > len?
296
send_buf_.get_unused_len();
300
// In case our send buffer is full, we have just to wait until
301
// previous send to complete...
305
// Read outgoing data from bio
306
len = ::BIO_read( ssl_bio_, send_buf_.get_unused_start(), len);
310
unsigned char *data_start = send_buf_.get_unused_start();
311
send_buf_.data_added(len);
313
BOOST_ASSERT(strand_);
317
asio::buffer(data_start, len),
322
&openssl_operation::async_write_handler,
326
asio::placeholders::error,
327
asio::placeholders::bytes_transferred
334
else if (!BIO_should_retry(ssl_bio_))
336
// Seems like fatal error
337
// reading from SSL BIO has failed...
338
handler_(asio::error::no_recovery, 0);
343
if (is_operation_done)
345
// Finish the operation, with success
346
handler_(asio::error_code(), rc);
350
// OPeration is not done and writing to net has been made...
351
// start operation again
357
void async_write_handler(bool is_operation_done, int rc,
358
const asio::error_code& error, size_t bytes_sent)
362
// Remove data from send buffer
363
send_buf_.data_removed(bytes_sent);
365
if (is_operation_done)
366
handler_(asio::error_code(), rc);
368
// Since the operation was not completed, try it again...
378
BOOST_ASSERT(strand_);
379
socket_.async_read_some
381
asio::buffer(recv_buf_.get_unused_start(),
382
recv_buf_.get_unused_len()),
387
&openssl_operation::async_read_handler,
389
asio::placeholders::error,
390
asio::placeholders::bytes_transferred
397
void async_read_handler(const asio::error_code& error,
402
recv_buf_.data_added(bytes_recvd);
404
// Pass the received data to SSL
405
int written = ::BIO_write
408
recv_buf_.get_data_start(),
409
recv_buf_.get_data_len()
414
recv_buf_.data_removed(written);
416
else if (written < 0)
418
if (!BIO_should_retry(ssl_bio_))
420
// Some serios error with BIO....
421
handler_(asio::error::no_recovery, 0);
426
// and try the SSL primitive again
431
// Error in network level...
432
// SSL can't continue either...
437
// Syncronous functions...
438
int do_sync_write(bool is_operation_done, int rc)
440
int len = ::BIO_ctrl_pending( ssl_bio_ );
443
// There is something to write into net, do it...
444
len = (int)send_buf_.get_unused_len() > len?
446
send_buf_.get_unused_len();
448
// Read outgoing data from bio
449
len = ::BIO_read( ssl_bio_, send_buf_.get_unused_start(), len);
453
size_t sent_len = asio::write(
455
asio::buffer(send_buf_.get_unused_start(), len)
458
send_buf_.data_added(len);
459
send_buf_.data_removed(sent_len);
461
else if (!BIO_should_retry(ssl_bio_))
463
// Seems like fatal error
464
// reading from SSL BIO has failed...
465
throw asio::system_error(asio::error::no_recovery);
469
if (is_operation_done)
470
// Finish the operation, with success
473
// Operation is not finished, start again.
479
size_t len = socket_.read_some
481
asio::buffer(recv_buf_.get_unused_start(),
482
recv_buf_.get_unused_len())
486
recv_buf_.data_added(len);
488
// Pass the received data to SSL
489
int written = ::BIO_write
492
recv_buf_.get_data_start(),
493
recv_buf_.get_data_len()
498
recv_buf_.data_removed(written);
500
else if (written < 0)
502
if (!BIO_should_retry(ssl_bio_))
504
// Some serios error with BIO....
505
throw asio::system_error(asio::error::no_recovery);
509
// Try the operation again
512
}; // class openssl_operation
514
} // namespace detail
518
#include "asio/detail/pop_options.hpp"
520
#endif // ASIO_SSL_DETAIL_OPENSSL_OPERATION_HPP