Statistics
| Revision:

root / tmp / org.txm.statsengine.r.core.win32 / res / win32 / library / BH / include / boost / asio / basic_socket_streambuf.hpp @ 2486

History | View | Annotate | Download (16.1 kB)

1
//
2
// basic_socket_streambuf.hpp
3
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
4
//
5
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff 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 BOOST_ASIO_BASIC_SOCKET_STREAMBUF_HPP
12
#define BOOST_ASIO_BASIC_SOCKET_STREAMBUF_HPP
13

    
14
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15
# pragma once
16
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17

    
18
#include <boost/asio/detail/config.hpp>
19

    
20
#if !defined(BOOST_ASIO_NO_IOSTREAM)
21

    
22
#include <streambuf>
23
#include <boost/asio/basic_socket.hpp>
24
#include <boost/asio/deadline_timer_service.hpp>
25
#include <boost/asio/detail/array.hpp>
26
#include <boost/asio/detail/throw_error.hpp>
27
#include <boost/asio/io_service.hpp>
28
#include <boost/asio/stream_socket_service.hpp>
29

    
30
#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
31
# include <boost/asio/deadline_timer.hpp>
32
#else
33
# include <boost/asio/steady_timer.hpp>
34
#endif
35

    
36
#if !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
37

    
38
# include <boost/asio/detail/variadic_templates.hpp>
39

    
40
// A macro that should expand to:
41
//   template <typename T1, ..., typename Tn>
42
//   basic_socket_streambuf<Protocol, StreamSocketService,
43
//     Time, TimeTraits, TimerService>* connect(
44
//       T1 x1, ..., Tn xn)
45
//   {
46
//     init_buffers();
47
//     this->basic_socket<Protocol, StreamSocketService>::close(ec_);
48
//     typedef typename Protocol::resolver resolver_type;
49
//     typedef typename resolver_type::query resolver_query;
50
//     resolver_query query(x1, ..., xn);
51
//     resolve_and_connect(query);
52
//     return !ec_ ? this : 0;
53
//   }
54
// This macro should only persist within this file.
55

    
56
# define BOOST_ASIO_PRIVATE_CONNECT_DEF(n) \
57
  template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \
58
  basic_socket_streambuf<Protocol, StreamSocketService, \
59
    Time, TimeTraits, TimerService>* connect(BOOST_ASIO_VARIADIC_PARAMS(n)) \
60
  { \
61
    init_buffers(); \
62
    this->basic_socket<Protocol, StreamSocketService>::close(ec_); \
63
    typedef typename Protocol::resolver resolver_type; \
64
    typedef typename resolver_type::query resolver_query; \
65
    resolver_query query(BOOST_ASIO_VARIADIC_ARGS(n)); \
66
    resolve_and_connect(query); \
67
    return !ec_ ? this : 0; \
68
  } \
69
  /**/
70

    
71
#endif // !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
72

    
73
#include <boost/asio/detail/push_options.hpp>
74

    
75
namespace boost {
76
namespace asio {
77
namespace detail {
78

    
79
// A separate base class is used to ensure that the io_service is initialised
80
// prior to the basic_socket_streambuf's basic_socket base class.
81
class socket_streambuf_base
82
{
83
protected:
84
  io_service io_service_;
85
};
86

    
87
} // namespace detail
88

    
89
/// Iostream streambuf for a socket.
90
template <typename Protocol,
91
    typename StreamSocketService = stream_socket_service<Protocol>,
92
#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \
93
  || defined(GENERATING_DOCUMENTATION)
94
    typename Time = boost::posix_time::ptime,
95
    typename TimeTraits = boost::asio::time_traits<Time>,
96
    typename TimerService = deadline_timer_service<Time, TimeTraits> >
97
#else
98
    typename Time = steady_timer::clock_type,
99
    typename TimeTraits = steady_timer::traits_type,
100
    typename TimerService = steady_timer::service_type>
101
#endif
102
class basic_socket_streambuf
103
  : public std::streambuf,
104
    private detail::socket_streambuf_base,
105
    public basic_socket<Protocol, StreamSocketService>
106
{
107
private:
108
  // These typedefs are intended keep this class's implementation independent
109
  // of whether it's using Boost.DateTime, Boost.Chrono or std::chrono.
110
#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
111
  typedef TimeTraits traits_helper;
112
#else
113
  typedef detail::chrono_time_traits<Time, TimeTraits> traits_helper;
114
#endif
115

    
116
public:
117
  /// The endpoint type.
118
  typedef typename Protocol::endpoint endpoint_type;
119

    
120
#if defined(GENERATING_DOCUMENTATION)
121
  /// The time type.
122
  typedef typename TimeTraits::time_type time_type;
123

    
124
  /// The duration type.
125
  typedef typename TimeTraits::duration_type duration_type;
126
#else
127
  typedef typename traits_helper::time_type time_type;
128
  typedef typename traits_helper::duration_type duration_type;
129
#endif
130

    
131
  /// Construct a basic_socket_streambuf without establishing a connection.
132
  basic_socket_streambuf()
133
    : basic_socket<Protocol, StreamSocketService>(
134
        this->detail::socket_streambuf_base::io_service_),
135
      unbuffered_(false),
136
      timer_service_(0),
137
      timer_state_(no_timer)
138
  {
139
    init_buffers();
140
  }
141

    
142
  /// Destructor flushes buffered data.
143
  virtual ~basic_socket_streambuf()
144
  {
145
    if (pptr() != pbase())
146
      overflow(traits_type::eof());
147

    
148
    destroy_timer();
149
  }
150

    
151
  /// Establish a connection.
152
  /**
153
   * This function establishes a connection to the specified endpoint.
154
   *
155
   * @return \c this if a connection was successfully established, a null
156
   * pointer otherwise.
157
   */
158
  basic_socket_streambuf<Protocol, StreamSocketService,
159
    Time, TimeTraits, TimerService>* connect(
160
      const endpoint_type& endpoint)
161
  {
162
    init_buffers();
163

    
164
    this->basic_socket<Protocol, StreamSocketService>::close(ec_);
165

    
166
    if (timer_state_ == timer_has_expired)
167
    {
168
      ec_ = boost::asio::error::operation_aborted;
169
      return 0;
170
    }
171

    
172
    io_handler handler = { this };
173
    this->basic_socket<Protocol, StreamSocketService>::async_connect(
174
        endpoint, handler);
175

    
176
    ec_ = boost::asio::error::would_block;
177
    this->get_service().get_io_service().reset();
178
    do this->get_service().get_io_service().run_one();
179
    while (ec_ == boost::asio::error::would_block);
180

    
181
    return !ec_ ? this : 0;
182
  }
183

    
184
#if defined(GENERATING_DOCUMENTATION)
185
  /// Establish a connection.
186
  /**
187
   * This function automatically establishes a connection based on the supplied
188
   * resolver query parameters. The arguments are used to construct a resolver
189
   * query object.
190
   *
191
   * @return \c this if a connection was successfully established, a null
192
   * pointer otherwise.
193
   */
194
  template <typename T1, ..., typename TN>
195
  basic_socket_streambuf<Protocol, StreamSocketService>* connect(
196
      T1 t1, ..., TN tn);
197
#elif defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
198
  template <typename... T>
199
  basic_socket_streambuf<Protocol, StreamSocketService,
200
    Time, TimeTraits, TimerService>* connect(T... x)
201
  {
202
    init_buffers();
203
    this->basic_socket<Protocol, StreamSocketService>::close(ec_);
204
    typedef typename Protocol::resolver resolver_type;
205
    typedef typename resolver_type::query resolver_query;
206
    resolver_query query(x...);
207
    resolve_and_connect(query);
208
    return !ec_ ? this : 0;
209
  }
210
#else
211
  BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_CONNECT_DEF)
212
#endif
213

    
214
  /// Close the connection.
215
  /**
216
   * @return \c this if a connection was successfully established, a null
217
   * pointer otherwise.
218
   */
219
  basic_socket_streambuf<Protocol, StreamSocketService,
220
    Time, TimeTraits, TimerService>* close()
221
  {
222
    sync();
223
    this->basic_socket<Protocol, StreamSocketService>::close(ec_);
224
    if (!ec_)
225
      init_buffers();
226
    return !ec_ ? this : 0;
227
  }
228

    
229
  /// Get the last error associated with the stream buffer.
230
  /**
231
   * @return An \c error_code corresponding to the last error from the stream
232
   * buffer.
233
   */
234
  const boost::system::error_code& puberror() const
235
  {
236
    return error();
237
  }
238

    
239
  /// Get the stream buffer's expiry time as an absolute time.
240
  /**
241
   * @return An absolute time value representing the stream buffer's expiry
242
   * time.
243
   */
244
  time_type expires_at() const
245
  {
246
    return timer_service_
247
      ? timer_service_->expires_at(timer_implementation_)
248
      : time_type();
249
  }
250

    
251
  /// Set the stream buffer's expiry time as an absolute time.
252
  /**
253
   * This function sets the expiry time associated with the stream. Stream
254
   * operations performed after this time (where the operations cannot be
255
   * completed using the internal buffers) will fail with the error
256
   * boost::asio::error::operation_aborted.
257
   *
258
   * @param expiry_time The expiry time to be used for the stream.
259
   */
260
  void expires_at(const time_type& expiry_time)
261
  {
262
    construct_timer();
263

    
264
    boost::system::error_code ec;
265
    timer_service_->expires_at(timer_implementation_, expiry_time, ec);
266
    boost::asio::detail::throw_error(ec, "expires_at");
267

    
268
    start_timer();
269
  }
270

    
271
  /// Get the stream buffer's expiry time relative to now.
272
  /**
273
   * @return A relative time value representing the stream buffer's expiry time.
274
   */
275
  duration_type expires_from_now() const
276
  {
277
    return traits_helper::subtract(expires_at(), traits_helper::now());
278
  }
279

    
280
  /// Set the stream buffer's expiry time relative to now.
281
  /**
282
   * This function sets the expiry time associated with the stream. Stream
283
   * operations performed after this time (where the operations cannot be
284
   * completed using the internal buffers) will fail with the error
285
   * boost::asio::error::operation_aborted.
286
   *
287
   * @param expiry_time The expiry time to be used for the timer.
288
   */
289
  void expires_from_now(const duration_type& expiry_time)
290
  {
291
    construct_timer();
292

    
293
    boost::system::error_code ec;
294
    timer_service_->expires_from_now(timer_implementation_, expiry_time, ec);
295
    boost::asio::detail::throw_error(ec, "expires_from_now");
296

    
297
    start_timer();
298
  }
299

    
300
protected:
301
  int_type underflow()
302
  {
303
    if (gptr() == egptr())
304
    {
305
      if (timer_state_ == timer_has_expired)
306
      {
307
        ec_ = boost::asio::error::operation_aborted;
308
        return traits_type::eof();
309
      }
310

    
311
      io_handler handler = { this };
312
      this->get_service().async_receive(this->get_implementation(),
313
          boost::asio::buffer(boost::asio::buffer(get_buffer_) + putback_max),
314
          0, handler);
315

    
316
      ec_ = boost::asio::error::would_block;
317
      this->get_service().get_io_service().reset();
318
      do this->get_service().get_io_service().run_one();
319
      while (ec_ == boost::asio::error::would_block);
320
      if (ec_)
321
        return traits_type::eof();
322

    
323
      setg(&get_buffer_[0], &get_buffer_[0] + putback_max,
324
          &get_buffer_[0] + putback_max + bytes_transferred_);
325
      return traits_type::to_int_type(*gptr());
326
    }
327
    else
328
    {
329
      return traits_type::eof();
330
    }
331
  }
332

    
333
  int_type overflow(int_type c)
334
  {
335
    if (unbuffered_)
336
    {
337
      if (traits_type::eq_int_type(c, traits_type::eof()))
338
      {
339
        // Nothing to do.
340
        return traits_type::not_eof(c);
341
      }
342
      else
343
      {
344
        if (timer_state_ == timer_has_expired)
345
        {
346
          ec_ = boost::asio::error::operation_aborted;
347
          return traits_type::eof();
348
        }
349

    
350
        // Send the single character immediately.
351
        char_type ch = traits_type::to_char_type(c);
352
        io_handler handler = { this };
353
        this->get_service().async_send(this->get_implementation(),
354
            boost::asio::buffer(&ch, sizeof(char_type)), 0, handler);
355

    
356
        ec_ = boost::asio::error::would_block;
357
        this->get_service().get_io_service().reset();
358
        do this->get_service().get_io_service().run_one();
359
        while (ec_ == boost::asio::error::would_block);
360
        if (ec_)
361
          return traits_type::eof();
362

    
363
        return c;
364
      }
365
    }
366
    else
367
    {
368
      // Send all data in the output buffer.
369
      boost::asio::const_buffer buffer =
370
        boost::asio::buffer(pbase(), pptr() - pbase());
371
      while (boost::asio::buffer_size(buffer) > 0)
372
      {
373
        if (timer_state_ == timer_has_expired)
374
        {
375
          ec_ = boost::asio::error::operation_aborted;
376
          return traits_type::eof();
377
        }
378

    
379
        io_handler handler = { this };
380
        this->get_service().async_send(this->get_implementation(),
381
            boost::asio::buffer(buffer), 0, handler);
382

    
383
        ec_ = boost::asio::error::would_block;
384
        this->get_service().get_io_service().reset();
385
        do this->get_service().get_io_service().run_one();
386
        while (ec_ == boost::asio::error::would_block);
387
        if (ec_)
388
          return traits_type::eof();
389

    
390
        buffer = buffer + bytes_transferred_;
391
      }
392
      setp(&put_buffer_[0], &put_buffer_[0] + put_buffer_.size());
393

    
394
      // If the new character is eof then our work here is done.
395
      if (traits_type::eq_int_type(c, traits_type::eof()))
396
        return traits_type::not_eof(c);
397

    
398
      // Add the new character to the output buffer.
399
      *pptr() = traits_type::to_char_type(c);
400
      pbump(1);
401
      return c;
402
    }
403
  }
404

    
405
  int sync()
406
  {
407
    return overflow(traits_type::eof());
408
  }
409

    
410
  std::streambuf* setbuf(char_type* s, std::streamsize n)
411
  {
412
    if (pptr() == pbase() && s == 0 && n == 0)
413
    {
414
      unbuffered_ = true;
415
      setp(0, 0);
416
      return this;
417
    }
418

    
419
    return 0;
420
  }
421

    
422
  /// Get the last error associated with the stream buffer.
423
  /**
424
   * @return An \c error_code corresponding to the last error from the stream
425
   * buffer.
426
   */
427
  virtual const boost::system::error_code& error() const
428
  {
429
    return ec_;
430
  }
431

    
432
private:
433
  void init_buffers()
434
  {
435
    setg(&get_buffer_[0],
436
        &get_buffer_[0] + putback_max,
437
        &get_buffer_[0] + putback_max);
438
    if (unbuffered_)
439
      setp(0, 0);
440
    else
441
      setp(&put_buffer_[0], &put_buffer_[0] + put_buffer_.size());
442
  }
443

    
444
  template <typename ResolverQuery>
445
  void resolve_and_connect(const ResolverQuery& query)
446
  {
447
    typedef typename Protocol::resolver resolver_type;
448
    typedef typename resolver_type::iterator iterator_type;
449
    resolver_type resolver(detail::socket_streambuf_base::io_service_);
450
    iterator_type i = resolver.resolve(query, ec_);
451
    if (!ec_)
452
    {
453
      iterator_type end;
454
      ec_ = boost::asio::error::host_not_found;
455
      while (ec_ && i != end)
456
      {
457
        this->basic_socket<Protocol, StreamSocketService>::close(ec_);
458

    
459
        if (timer_state_ == timer_has_expired)
460
        {
461
          ec_ = boost::asio::error::operation_aborted;
462
          return;
463
        }
464

    
465
        io_handler handler = { this };
466
        this->basic_socket<Protocol, StreamSocketService>::async_connect(
467
            *i, handler);
468

    
469
        ec_ = boost::asio::error::would_block;
470
        this->get_service().get_io_service().reset();
471
        do this->get_service().get_io_service().run_one();
472
        while (ec_ == boost::asio::error::would_block);
473

    
474
        ++i;
475
      }
476
    }
477
  }
478

    
479
  struct io_handler;
480
  friend struct io_handler;
481
  struct io_handler
482
  {
483
    basic_socket_streambuf* this_;
484

    
485
    void operator()(const boost::system::error_code& ec,
486
        std::size_t bytes_transferred = 0)
487
    {
488
      this_->ec_ = ec;
489
      this_->bytes_transferred_ = bytes_transferred;
490
    }
491
  };
492

    
493
  struct timer_handler;
494
  friend struct timer_handler;
495
  struct timer_handler
496
  {
497
    basic_socket_streambuf* this_;
498

    
499
    void operator()(const boost::system::error_code&)
500
    {
501
      time_type now = traits_helper::now();
502

    
503
      time_type expiry_time = this_->timer_service_->expires_at(
504
            this_->timer_implementation_);
505

    
506
      if (traits_helper::less_than(now, expiry_time))
507
      {
508
        this_->timer_state_ = timer_is_pending;
509
        this_->timer_service_->async_wait(this_->timer_implementation_, *this);
510
      }
511
      else
512
      {
513
        this_->timer_state_ = timer_has_expired;
514
        boost::system::error_code ec;
515
        this_->basic_socket<Protocol, StreamSocketService>::close(ec);
516
      }
517
    }
518
  };
519

    
520
  void construct_timer()
521
  {
522
    if (timer_service_ == 0)
523
    {
524
      TimerService& timer_service = use_service<TimerService>(
525
          detail::socket_streambuf_base::io_service_);
526
      timer_service.construct(timer_implementation_);
527
      timer_service_ = &timer_service;
528
    }
529
  }
530

    
531
  void destroy_timer()
532
  {
533
    if (timer_service_)
534
      timer_service_->destroy(timer_implementation_);
535
  }
536

    
537
  void start_timer()
538
  {
539
    if (timer_state_ != timer_is_pending)
540
    {
541
      timer_handler handler = { this };
542
      handler(boost::system::error_code());
543
    }
544
  }
545

    
546
  enum { putback_max = 8 };
547
  enum { buffer_size = 512 };
548
  boost::asio::detail::array<char, buffer_size> get_buffer_;
549
  boost::asio::detail::array<char, buffer_size> put_buffer_;
550
  bool unbuffered_;
551
  boost::system::error_code ec_;
552
  std::size_t bytes_transferred_;
553
  TimerService* timer_service_;
554
  typename TimerService::implementation_type timer_implementation_;
555
  enum state { no_timer, timer_is_pending, timer_has_expired } timer_state_;
556
};
557

    
558
} // namespace asio
559
} // namespace boost
560

    
561
#include <boost/asio/detail/pop_options.hpp>
562

    
563
#if !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
564
# undef BOOST_ASIO_PRIVATE_CONNECT_DEF
565
#endif // !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
566

    
567
#endif // !defined(BOOST_ASIO_NO_IOSTREAM)
568

    
569
#endif // BOOST_ASIO_BASIC_SOCKET_STREAMBUF_HPP