Chris@16
|
1 //
|
Chris@16
|
2 // ssl/old/detail/openssl_operation.hpp
|
Chris@16
|
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
Chris@16
|
4 //
|
Chris@16
|
5 // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
|
Chris@16
|
6 //
|
Chris@16
|
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
|
Chris@16
|
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
9 //
|
Chris@16
|
10
|
Chris@16
|
11 #ifndef BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_OPERATION_HPP
|
Chris@16
|
12 #define BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_OPERATION_HPP
|
Chris@16
|
13
|
Chris@16
|
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
Chris@16
|
15 # pragma once
|
Chris@16
|
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
Chris@16
|
17
|
Chris@16
|
18 #include <boost/asio/detail/config.hpp>
|
Chris@16
|
19 #include <boost/function.hpp>
|
Chris@16
|
20 #include <boost/bind.hpp>
|
Chris@16
|
21 #include <boost/asio/buffer.hpp>
|
Chris@16
|
22 #include <boost/asio/detail/assert.hpp>
|
Chris@16
|
23 #include <boost/asio/detail/socket_ops.hpp>
|
Chris@16
|
24 #include <boost/asio/placeholders.hpp>
|
Chris@16
|
25 #include <boost/asio/ssl/detail/openssl_types.hpp>
|
Chris@16
|
26 #include <boost/asio/ssl/error.hpp>
|
Chris@16
|
27 #include <boost/asio/strand.hpp>
|
Chris@16
|
28 #include <boost/system/system_error.hpp>
|
Chris@16
|
29 #include <boost/asio/write.hpp>
|
Chris@16
|
30
|
Chris@16
|
31 #include <boost/asio/detail/push_options.hpp>
|
Chris@16
|
32
|
Chris@16
|
33 namespace boost {
|
Chris@16
|
34 namespace asio {
|
Chris@16
|
35 namespace ssl {
|
Chris@16
|
36 namespace old {
|
Chris@16
|
37 namespace detail {
|
Chris@16
|
38
|
Chris@16
|
39 typedef boost::function<int (::SSL*)> ssl_primitive_func;
|
Chris@16
|
40 typedef boost::function<void (const boost::system::error_code&, int)>
|
Chris@16
|
41 user_handler_func;
|
Chris@16
|
42
|
Chris@16
|
43 // Network send_/recv buffer implementation
|
Chris@16
|
44 //
|
Chris@16
|
45 //
|
Chris@16
|
46 class net_buffer
|
Chris@16
|
47 {
|
Chris@16
|
48 static const int NET_BUF_SIZE = 16*1024 + 256; // SSL record size + spare
|
Chris@16
|
49
|
Chris@16
|
50 unsigned char buf_[NET_BUF_SIZE];
|
Chris@16
|
51 unsigned char* data_start_;
|
Chris@16
|
52 unsigned char* data_end_;
|
Chris@16
|
53
|
Chris@16
|
54 public:
|
Chris@16
|
55 net_buffer()
|
Chris@16
|
56 {
|
Chris@16
|
57 data_start_ = data_end_ = buf_;
|
Chris@16
|
58 }
|
Chris@16
|
59 unsigned char* get_unused_start() { return data_end_; }
|
Chris@16
|
60 unsigned char* get_data_start() { return data_start_; }
|
Chris@16
|
61 size_t get_unused_len() { return (NET_BUF_SIZE - (data_end_ - buf_)); }
|
Chris@16
|
62 size_t get_data_len() { return (data_end_ - data_start_); }
|
Chris@16
|
63 void data_added(size_t count)
|
Chris@16
|
64 {
|
Chris@16
|
65 data_end_ += count;
|
Chris@16
|
66 data_end_ = data_end_ > (buf_ + NET_BUF_SIZE)?
|
Chris@16
|
67 (buf_ + NET_BUF_SIZE):
|
Chris@16
|
68 data_end_;
|
Chris@16
|
69 }
|
Chris@16
|
70 void data_removed(size_t count)
|
Chris@16
|
71 {
|
Chris@16
|
72 data_start_ += count;
|
Chris@16
|
73 if (data_start_ >= data_end_) reset();
|
Chris@16
|
74 }
|
Chris@16
|
75 void reset() { data_start_ = buf_; data_end_ = buf_; }
|
Chris@16
|
76 bool has_data() { return (data_start_ < data_end_); }
|
Chris@16
|
77 }; // class net_buffer
|
Chris@16
|
78
|
Chris@16
|
79 //
|
Chris@16
|
80 // Operation class
|
Chris@16
|
81 //
|
Chris@16
|
82 //
|
Chris@16
|
83 template <typename Stream>
|
Chris@16
|
84 class openssl_operation
|
Chris@16
|
85 {
|
Chris@16
|
86 public:
|
Chris@16
|
87
|
Chris@16
|
88 // Constructor for asynchronous operations
|
Chris@16
|
89 openssl_operation(ssl_primitive_func primitive,
|
Chris@16
|
90 Stream& socket,
|
Chris@16
|
91 net_buffer& recv_buf,
|
Chris@16
|
92 SSL* session,
|
Chris@16
|
93 BIO* ssl_bio,
|
Chris@16
|
94 user_handler_func handler,
|
Chris@16
|
95 boost::asio::io_service::strand& strand
|
Chris@16
|
96 )
|
Chris@16
|
97 : primitive_(primitive)
|
Chris@16
|
98 , user_handler_(handler)
|
Chris@16
|
99 , strand_(&strand)
|
Chris@16
|
100 , recv_buf_(recv_buf)
|
Chris@16
|
101 , socket_(socket)
|
Chris@16
|
102 , ssl_bio_(ssl_bio)
|
Chris@16
|
103 , session_(session)
|
Chris@16
|
104 {
|
Chris@16
|
105 write_ = boost::bind(
|
Chris@16
|
106 &openssl_operation::do_async_write,
|
Chris@16
|
107 this, boost::arg<1>(), boost::arg<2>()
|
Chris@16
|
108 );
|
Chris@16
|
109 read_ = boost::bind(
|
Chris@16
|
110 &openssl_operation::do_async_read,
|
Chris@16
|
111 this
|
Chris@16
|
112 );
|
Chris@16
|
113 handler_= boost::bind(
|
Chris@16
|
114 &openssl_operation::async_user_handler,
|
Chris@16
|
115 this, boost::arg<1>(), boost::arg<2>()
|
Chris@16
|
116 );
|
Chris@16
|
117 }
|
Chris@16
|
118
|
Chris@16
|
119 // Constructor for synchronous operations
|
Chris@16
|
120 openssl_operation(ssl_primitive_func primitive,
|
Chris@16
|
121 Stream& socket,
|
Chris@16
|
122 net_buffer& recv_buf,
|
Chris@16
|
123 SSL* session,
|
Chris@16
|
124 BIO* ssl_bio)
|
Chris@16
|
125 : primitive_(primitive)
|
Chris@16
|
126 , strand_(0)
|
Chris@16
|
127 , recv_buf_(recv_buf)
|
Chris@16
|
128 , socket_(socket)
|
Chris@16
|
129 , ssl_bio_(ssl_bio)
|
Chris@16
|
130 , session_(session)
|
Chris@16
|
131 {
|
Chris@16
|
132 write_ = boost::bind(
|
Chris@16
|
133 &openssl_operation::do_sync_write,
|
Chris@16
|
134 this, boost::arg<1>(), boost::arg<2>()
|
Chris@16
|
135 );
|
Chris@16
|
136 read_ = boost::bind(
|
Chris@16
|
137 &openssl_operation::do_sync_read,
|
Chris@16
|
138 this
|
Chris@16
|
139 );
|
Chris@16
|
140 handler_ = boost::bind(
|
Chris@16
|
141 &openssl_operation::sync_user_handler,
|
Chris@16
|
142 this, boost::arg<1>(), boost::arg<2>()
|
Chris@16
|
143 );
|
Chris@16
|
144 }
|
Chris@16
|
145
|
Chris@16
|
146 // Start operation
|
Chris@16
|
147 // In case of asynchronous it returns 0, in sync mode returns success code
|
Chris@16
|
148 // or throws an error...
|
Chris@16
|
149 int start()
|
Chris@16
|
150 {
|
Chris@16
|
151 int rc = primitive_( session_ );
|
Chris@16
|
152
|
Chris@16
|
153 bool is_operation_done = (rc > 0);
|
Chris@16
|
154 // For connect/accept/shutdown, the operation
|
Chris@16
|
155 // is done, when return code is 1
|
Chris@16
|
156 // for write, it is done, when is retcode > 0
|
Chris@16
|
157 // for read, it is done when retcode > 0
|
Chris@16
|
158
|
Chris@16
|
159 int error_code = !is_operation_done ?
|
Chris@16
|
160 ::SSL_get_error( session_, rc ) :
|
Chris@16
|
161 0;
|
Chris@16
|
162 int sys_error_code = ERR_get_error();
|
Chris@16
|
163
|
Chris@16
|
164 if (error_code == SSL_ERROR_SSL)
|
Chris@16
|
165 return handler_(boost::system::error_code(
|
Chris@16
|
166 sys_error_code, boost::asio::error::get_ssl_category()), rc);
|
Chris@16
|
167
|
Chris@16
|
168 bool is_read_needed = (error_code == SSL_ERROR_WANT_READ);
|
Chris@16
|
169 bool is_write_needed = (error_code == SSL_ERROR_WANT_WRITE ||
|
Chris@16
|
170 ::BIO_ctrl_pending( ssl_bio_ ));
|
Chris@16
|
171 bool is_shut_down_received =
|
Chris@16
|
172 ((::SSL_get_shutdown( session_ ) & SSL_RECEIVED_SHUTDOWN) ==
|
Chris@16
|
173 SSL_RECEIVED_SHUTDOWN);
|
Chris@16
|
174 bool is_shut_down_sent =
|
Chris@16
|
175 ((::SSL_get_shutdown( session_ ) & SSL_SENT_SHUTDOWN) ==
|
Chris@16
|
176 SSL_SENT_SHUTDOWN);
|
Chris@16
|
177
|
Chris@16
|
178 if (is_shut_down_sent && is_shut_down_received
|
Chris@16
|
179 && is_operation_done && !is_write_needed)
|
Chris@16
|
180 // SSL connection is shut down cleanly
|
Chris@16
|
181 return handler_(boost::system::error_code(), 1);
|
Chris@16
|
182
|
Chris@16
|
183 if (is_shut_down_received && !is_operation_done)
|
Chris@16
|
184 // Shutdown has been requested, while we were reading or writing...
|
Chris@16
|
185 // abort our action...
|
Chris@16
|
186 return handler_(boost::asio::error::shut_down, 0);
|
Chris@16
|
187
|
Chris@16
|
188 if (!is_operation_done && !is_read_needed && !is_write_needed
|
Chris@16
|
189 && !is_shut_down_sent)
|
Chris@16
|
190 {
|
Chris@16
|
191 // The operation has failed... It is not completed and does
|
Chris@16
|
192 // not want network communication nor does want to send shutdown out...
|
Chris@16
|
193 if (error_code == SSL_ERROR_SYSCALL)
|
Chris@16
|
194 {
|
Chris@16
|
195 return handler_(boost::system::error_code(
|
Chris@16
|
196 sys_error_code, boost::asio::error::system_category), rc);
|
Chris@16
|
197 }
|
Chris@16
|
198 else
|
Chris@16
|
199 {
|
Chris@16
|
200 return handler_(boost::system::error_code(
|
Chris@16
|
201 sys_error_code, boost::asio::error::get_ssl_category()), rc);
|
Chris@16
|
202 }
|
Chris@16
|
203 }
|
Chris@16
|
204
|
Chris@16
|
205 if (!is_operation_done && !is_write_needed)
|
Chris@16
|
206 {
|
Chris@16
|
207 // We may have left over data that we can pass to SSL immediately
|
Chris@16
|
208 if (recv_buf_.get_data_len() > 0)
|
Chris@16
|
209 {
|
Chris@16
|
210 // Pass the buffered data to SSL
|
Chris@16
|
211 int written = ::BIO_write
|
Chris@16
|
212 (
|
Chris@16
|
213 ssl_bio_,
|
Chris@16
|
214 recv_buf_.get_data_start(),
|
Chris@16
|
215 recv_buf_.get_data_len()
|
Chris@16
|
216 );
|
Chris@16
|
217
|
Chris@16
|
218 if (written > 0)
|
Chris@16
|
219 {
|
Chris@16
|
220 recv_buf_.data_removed(written);
|
Chris@16
|
221 }
|
Chris@16
|
222 else if (written < 0)
|
Chris@16
|
223 {
|
Chris@16
|
224 if (!BIO_should_retry(ssl_bio_))
|
Chris@16
|
225 {
|
Chris@16
|
226 // Some serios error with BIO....
|
Chris@16
|
227 return handler_(boost::asio::error::no_recovery, 0);
|
Chris@16
|
228 }
|
Chris@16
|
229 }
|
Chris@16
|
230
|
Chris@16
|
231 return start();
|
Chris@16
|
232 }
|
Chris@16
|
233 else if (is_read_needed || (is_shut_down_sent && !is_shut_down_received))
|
Chris@16
|
234 {
|
Chris@16
|
235 return read_();
|
Chris@16
|
236 }
|
Chris@16
|
237 }
|
Chris@16
|
238
|
Chris@16
|
239 // Continue with operation, flush any SSL data out to network...
|
Chris@16
|
240 return write_(is_operation_done, rc);
|
Chris@16
|
241 }
|
Chris@16
|
242
|
Chris@16
|
243 // Private implementation
|
Chris@16
|
244 private:
|
Chris@16
|
245 typedef boost::function<int (const boost::system::error_code&, int)>
|
Chris@16
|
246 int_handler_func;
|
Chris@16
|
247 typedef boost::function<int (bool, int)> write_func;
|
Chris@16
|
248 typedef boost::function<int ()> read_func;
|
Chris@16
|
249
|
Chris@16
|
250 ssl_primitive_func primitive_;
|
Chris@16
|
251 user_handler_func user_handler_;
|
Chris@16
|
252 boost::asio::io_service::strand* strand_;
|
Chris@16
|
253 write_func write_;
|
Chris@16
|
254 read_func read_;
|
Chris@16
|
255 int_handler_func handler_;
|
Chris@16
|
256
|
Chris@16
|
257 net_buffer send_buf_; // buffers for network IO
|
Chris@16
|
258
|
Chris@16
|
259 // The recv buffer is owned by the stream, not the operation, since there can
|
Chris@16
|
260 // be left over bytes after passing the data up to the application, and these
|
Chris@16
|
261 // bytes need to be kept around for the next read operation issued by the
|
Chris@16
|
262 // application.
|
Chris@16
|
263 net_buffer& recv_buf_;
|
Chris@16
|
264
|
Chris@16
|
265 Stream& socket_;
|
Chris@16
|
266 BIO* ssl_bio_;
|
Chris@16
|
267 SSL* session_;
|
Chris@16
|
268
|
Chris@16
|
269 //
|
Chris@16
|
270 int sync_user_handler(const boost::system::error_code& error, int rc)
|
Chris@16
|
271 {
|
Chris@16
|
272 if (!error)
|
Chris@16
|
273 return rc;
|
Chris@16
|
274
|
Chris@16
|
275 throw boost::system::system_error(error);
|
Chris@16
|
276 }
|
Chris@16
|
277
|
Chris@16
|
278 int async_user_handler(boost::system::error_code error, int rc)
|
Chris@16
|
279 {
|
Chris@16
|
280 if (rc < 0)
|
Chris@16
|
281 {
|
Chris@16
|
282 if (!error)
|
Chris@16
|
283 error = boost::asio::error::no_recovery;
|
Chris@16
|
284 rc = 0;
|
Chris@16
|
285 }
|
Chris@16
|
286
|
Chris@16
|
287 user_handler_(error, rc);
|
Chris@16
|
288 return 0;
|
Chris@16
|
289 }
|
Chris@16
|
290
|
Chris@16
|
291 // Writes bytes asynchronously from SSL to NET
|
Chris@16
|
292 int do_async_write(bool is_operation_done, int rc)
|
Chris@16
|
293 {
|
Chris@16
|
294 int len = ::BIO_ctrl_pending( ssl_bio_ );
|
Chris@16
|
295 if ( len )
|
Chris@16
|
296 {
|
Chris@16
|
297 // There is something to write into net, do it...
|
Chris@16
|
298 len = (int)send_buf_.get_unused_len() > len?
|
Chris@16
|
299 len:
|
Chris@16
|
300 send_buf_.get_unused_len();
|
Chris@16
|
301
|
Chris@16
|
302 if (len == 0)
|
Chris@16
|
303 {
|
Chris@16
|
304 // In case our send buffer is full, we have just to wait until
|
Chris@16
|
305 // previous send to complete...
|
Chris@16
|
306 return 0;
|
Chris@16
|
307 }
|
Chris@16
|
308
|
Chris@16
|
309 // Read outgoing data from bio
|
Chris@16
|
310 len = ::BIO_read( ssl_bio_, send_buf_.get_unused_start(), len);
|
Chris@16
|
311
|
Chris@16
|
312 if (len > 0)
|
Chris@16
|
313 {
|
Chris@16
|
314 unsigned char *data_start = send_buf_.get_unused_start();
|
Chris@16
|
315 send_buf_.data_added(len);
|
Chris@16
|
316
|
Chris@16
|
317 BOOST_ASIO_ASSERT(strand_);
|
Chris@16
|
318 boost::asio::async_write
|
Chris@16
|
319 (
|
Chris@16
|
320 socket_,
|
Chris@16
|
321 boost::asio::buffer(data_start, len),
|
Chris@16
|
322 strand_->wrap
|
Chris@16
|
323 (
|
Chris@16
|
324 boost::bind
|
Chris@16
|
325 (
|
Chris@16
|
326 &openssl_operation::async_write_handler,
|
Chris@16
|
327 this,
|
Chris@16
|
328 is_operation_done,
|
Chris@16
|
329 rc,
|
Chris@16
|
330 boost::asio::placeholders::error,
|
Chris@16
|
331 boost::asio::placeholders::bytes_transferred
|
Chris@16
|
332 )
|
Chris@16
|
333 )
|
Chris@16
|
334 );
|
Chris@16
|
335
|
Chris@16
|
336 return 0;
|
Chris@16
|
337 }
|
Chris@16
|
338 else if (!BIO_should_retry(ssl_bio_))
|
Chris@16
|
339 {
|
Chris@16
|
340 // Seems like fatal error
|
Chris@16
|
341 // reading from SSL BIO has failed...
|
Chris@16
|
342 handler_(boost::asio::error::no_recovery, 0);
|
Chris@16
|
343 return 0;
|
Chris@16
|
344 }
|
Chris@16
|
345 }
|
Chris@16
|
346
|
Chris@16
|
347 if (is_operation_done)
|
Chris@16
|
348 {
|
Chris@16
|
349 // Finish the operation, with success
|
Chris@16
|
350 handler_(boost::system::error_code(), rc);
|
Chris@16
|
351 return 0;
|
Chris@16
|
352 }
|
Chris@16
|
353
|
Chris@16
|
354 // OPeration is not done and writing to net has been made...
|
Chris@16
|
355 // start operation again
|
Chris@16
|
356 start();
|
Chris@16
|
357
|
Chris@16
|
358 return 0;
|
Chris@16
|
359 }
|
Chris@16
|
360
|
Chris@16
|
361 void async_write_handler(bool is_operation_done, int rc,
|
Chris@16
|
362 const boost::system::error_code& error, size_t bytes_sent)
|
Chris@16
|
363 {
|
Chris@16
|
364 if (!error)
|
Chris@16
|
365 {
|
Chris@16
|
366 // Remove data from send buffer
|
Chris@16
|
367 send_buf_.data_removed(bytes_sent);
|
Chris@16
|
368
|
Chris@16
|
369 if (is_operation_done)
|
Chris@16
|
370 handler_(boost::system::error_code(), rc);
|
Chris@16
|
371 else
|
Chris@16
|
372 // Since the operation was not completed, try it again...
|
Chris@16
|
373 start();
|
Chris@16
|
374 }
|
Chris@16
|
375 else
|
Chris@16
|
376 handler_(error, rc);
|
Chris@16
|
377 }
|
Chris@16
|
378
|
Chris@16
|
379 int do_async_read()
|
Chris@16
|
380 {
|
Chris@16
|
381 // Wait for new data
|
Chris@16
|
382 BOOST_ASIO_ASSERT(strand_);
|
Chris@16
|
383 socket_.async_read_some
|
Chris@16
|
384 (
|
Chris@16
|
385 boost::asio::buffer(recv_buf_.get_unused_start(),
|
Chris@16
|
386 recv_buf_.get_unused_len()),
|
Chris@16
|
387 strand_->wrap
|
Chris@16
|
388 (
|
Chris@16
|
389 boost::bind
|
Chris@16
|
390 (
|
Chris@16
|
391 &openssl_operation::async_read_handler,
|
Chris@16
|
392 this,
|
Chris@16
|
393 boost::asio::placeholders::error,
|
Chris@16
|
394 boost::asio::placeholders::bytes_transferred
|
Chris@16
|
395 )
|
Chris@16
|
396 )
|
Chris@16
|
397 );
|
Chris@16
|
398 return 0;
|
Chris@16
|
399 }
|
Chris@16
|
400
|
Chris@16
|
401 void async_read_handler(const boost::system::error_code& error,
|
Chris@16
|
402 size_t bytes_recvd)
|
Chris@16
|
403 {
|
Chris@16
|
404 if (!error)
|
Chris@16
|
405 {
|
Chris@16
|
406 recv_buf_.data_added(bytes_recvd);
|
Chris@16
|
407
|
Chris@16
|
408 // Pass the received data to SSL
|
Chris@16
|
409 int written = ::BIO_write
|
Chris@16
|
410 (
|
Chris@16
|
411 ssl_bio_,
|
Chris@16
|
412 recv_buf_.get_data_start(),
|
Chris@16
|
413 recv_buf_.get_data_len()
|
Chris@16
|
414 );
|
Chris@16
|
415
|
Chris@16
|
416 if (written > 0)
|
Chris@16
|
417 {
|
Chris@16
|
418 recv_buf_.data_removed(written);
|
Chris@16
|
419 }
|
Chris@16
|
420 else if (written < 0)
|
Chris@16
|
421 {
|
Chris@16
|
422 if (!BIO_should_retry(ssl_bio_))
|
Chris@16
|
423 {
|
Chris@16
|
424 // Some serios error with BIO....
|
Chris@16
|
425 handler_(boost::asio::error::no_recovery, 0);
|
Chris@16
|
426 return;
|
Chris@16
|
427 }
|
Chris@16
|
428 }
|
Chris@16
|
429
|
Chris@16
|
430 // and try the SSL primitive again
|
Chris@16
|
431 start();
|
Chris@16
|
432 }
|
Chris@16
|
433 else
|
Chris@16
|
434 {
|
Chris@16
|
435 // Error in network level...
|
Chris@16
|
436 // SSL can't continue either...
|
Chris@16
|
437 handler_(error, 0);
|
Chris@16
|
438 }
|
Chris@16
|
439 }
|
Chris@16
|
440
|
Chris@16
|
441 // Syncronous functions...
|
Chris@16
|
442 int do_sync_write(bool is_operation_done, int rc)
|
Chris@16
|
443 {
|
Chris@16
|
444 int len = ::BIO_ctrl_pending( ssl_bio_ );
|
Chris@16
|
445 if ( len )
|
Chris@16
|
446 {
|
Chris@16
|
447 // There is something to write into net, do it...
|
Chris@16
|
448 len = (int)send_buf_.get_unused_len() > len?
|
Chris@16
|
449 len:
|
Chris@16
|
450 send_buf_.get_unused_len();
|
Chris@16
|
451
|
Chris@16
|
452 // Read outgoing data from bio
|
Chris@16
|
453 len = ::BIO_read( ssl_bio_, send_buf_.get_unused_start(), len);
|
Chris@16
|
454
|
Chris@16
|
455 if (len > 0)
|
Chris@16
|
456 {
|
Chris@16
|
457 size_t sent_len = boost::asio::write(
|
Chris@16
|
458 socket_,
|
Chris@16
|
459 boost::asio::buffer(send_buf_.get_unused_start(), len)
|
Chris@16
|
460 );
|
Chris@16
|
461
|
Chris@16
|
462 send_buf_.data_added(len);
|
Chris@16
|
463 send_buf_.data_removed(sent_len);
|
Chris@16
|
464 }
|
Chris@16
|
465 else if (!BIO_should_retry(ssl_bio_))
|
Chris@16
|
466 {
|
Chris@16
|
467 // Seems like fatal error
|
Chris@16
|
468 // reading from SSL BIO has failed...
|
Chris@16
|
469 throw boost::system::system_error(boost::asio::error::no_recovery);
|
Chris@16
|
470 }
|
Chris@16
|
471 }
|
Chris@16
|
472
|
Chris@16
|
473 if (is_operation_done)
|
Chris@16
|
474 // Finish the operation, with success
|
Chris@16
|
475 return rc;
|
Chris@16
|
476
|
Chris@16
|
477 // Operation is not finished, start again.
|
Chris@16
|
478 return start();
|
Chris@16
|
479 }
|
Chris@16
|
480
|
Chris@16
|
481 int do_sync_read()
|
Chris@16
|
482 {
|
Chris@16
|
483 size_t len = socket_.read_some
|
Chris@16
|
484 (
|
Chris@16
|
485 boost::asio::buffer(recv_buf_.get_unused_start(),
|
Chris@16
|
486 recv_buf_.get_unused_len())
|
Chris@16
|
487 );
|
Chris@16
|
488
|
Chris@16
|
489 // Write data to ssl
|
Chris@16
|
490 recv_buf_.data_added(len);
|
Chris@16
|
491
|
Chris@16
|
492 // Pass the received data to SSL
|
Chris@16
|
493 int written = ::BIO_write
|
Chris@16
|
494 (
|
Chris@16
|
495 ssl_bio_,
|
Chris@16
|
496 recv_buf_.get_data_start(),
|
Chris@16
|
497 recv_buf_.get_data_len()
|
Chris@16
|
498 );
|
Chris@16
|
499
|
Chris@16
|
500 if (written > 0)
|
Chris@16
|
501 {
|
Chris@16
|
502 recv_buf_.data_removed(written);
|
Chris@16
|
503 }
|
Chris@16
|
504 else if (written < 0)
|
Chris@16
|
505 {
|
Chris@16
|
506 if (!BIO_should_retry(ssl_bio_))
|
Chris@16
|
507 {
|
Chris@16
|
508 // Some serios error with BIO....
|
Chris@16
|
509 throw boost::system::system_error(boost::asio::error::no_recovery);
|
Chris@16
|
510 }
|
Chris@16
|
511 }
|
Chris@16
|
512
|
Chris@16
|
513 // Try the operation again
|
Chris@16
|
514 return start();
|
Chris@16
|
515 }
|
Chris@16
|
516 }; // class openssl_operation
|
Chris@16
|
517
|
Chris@16
|
518 } // namespace detail
|
Chris@16
|
519 } // namespace old
|
Chris@16
|
520 } // namespace ssl
|
Chris@16
|
521 } // namespace asio
|
Chris@16
|
522 } // namespace boost
|
Chris@16
|
523
|
Chris@16
|
524 #include <boost/asio/detail/pop_options.hpp>
|
Chris@16
|
525
|
Chris@16
|
526 #endif // BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_OPERATION_HPP
|