~cmiller/ubuntu/quantal/deluge/fix-parameter-move-storage

« back to all changes in this revision

Viewing changes to libtorrent/include/asio/ssl/detail/openssl_operation.hpp

  • Committer: Bazaar Package Importer
  • Author(s): Cristian Greco
  • Date: 2009-11-13 02:39:45 UTC
  • mfrom: (4.1.7 squeeze)
  • Revision ID: james.westby@ubuntu.com-20091113023945-te1bybo2912ejzuc
Tags: 1.2.0~rc3-4
* debian/control: bump build-dep on python-setuptools to (>= 0.6c9).
* debian/patches:
  - 25_r5921_fastresume_files.patch
    new, should fix problems with fresh configs;
  - 30_r5931_ipc_lockfile.patch:
    new, should fix an issue where Deluge will fail to start if there is a
    stale ipc lockfile. (Closes: #555849)

Show diffs side-by-side

added added

removed removed

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