Realistic 3D camera system
3D camera system components
basic_socket_streambuf.hpp
Go to the documentation of this file.
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 ASIO_BASIC_SOCKET_STREAMBUF_HPP
12 #define 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 "asio/detail/config.hpp"
19 
20 #if !defined(ASIO_NO_IOSTREAM)
21 
22 #include <streambuf>
23 #include "asio/basic_socket.hpp"
25 #include "asio/detail/array.hpp"
27 #include "asio/io_service.hpp"
29 
30 #if defined(ASIO_HAS_BOOST_DATE_TIME)
31 # include "asio/deadline_timer.hpp"
32 #else
33 # include "asio/steady_timer.hpp"
34 #endif
35 
36 #if !defined(ASIO_HAS_VARIADIC_TEMPLATES)
37 
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 ASIO_PRIVATE_CONNECT_DEF(n) \
57  template <ASIO_VARIADIC_TPARAMS(n)> \
58  basic_socket_streambuf<Protocol, StreamSocketService, \
59  Time, TimeTraits, TimerService>* connect(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(ASIO_VARIADIC_ARGS(n)); \
66  resolve_and_connect(query); \
67  return !ec_ ? this : 0; \
68  } \
69 
70 
71 #endif // !defined(ASIO_HAS_VARIADIC_TEMPLATES)
72 
74 
75 namespace asio {
76 namespace detail {
77 
78 // A separate base class is used to ensure that the io_service is initialised
79 // prior to the basic_socket_streambuf's basic_socket base class.
81 {
82 protected:
84 };
85 
86 } // namespace detail
87 
89 template <typename Protocol,
90  typename StreamSocketService = stream_socket_service<Protocol>,
91 #if defined(ASIO_HAS_BOOST_DATE_TIME) \
92  || defined(GENERATING_DOCUMENTATION)
93  typename Time = boost::posix_time::ptime,
94  typename TimeTraits = asio::time_traits<Time>,
95  typename TimerService = deadline_timer_service<Time, TimeTraits> >
96 #else
97  typename Time = steady_timer::clock_type,
98  typename TimeTraits = steady_timer::traits_type,
99  typename TimerService = steady_timer::service_type>
100 #endif
102  : public std::streambuf,
104  public basic_socket<Protocol, StreamSocketService>
105 {
106 private:
107  // These typedefs are intended keep this class's implementation independent
108  // of whether it's using Boost.DateTime, Boost.Chrono or std::chrono.
109 #if defined(ASIO_HAS_BOOST_DATE_TIME)
110  typedef TimeTraits traits_helper;
111 #else
112  typedef detail::chrono_time_traits<Time, TimeTraits> traits_helper;
113 #endif
114 
115 public:
117  typedef typename Protocol::endpoint endpoint_type;
118 
119 #if defined(GENERATING_DOCUMENTATION)
120  typedef typename TimeTraits::time_type time_type;
122 
124  typedef typename TimeTraits::duration_type duration_type;
125 #else
128 #endif
129 
132  : basic_socket<Protocol, StreamSocketService>(
133  this->detail::socket_streambuf_base::io_service_),
134  unbuffered_(false),
135  timer_service_(0),
136  timer_state_(no_timer)
137  {
138  init_buffers();
139  }
140 
143  {
144  if (pptr() != pbase())
145  overflow(traits_type::eof());
146 
147  destroy_timer();
148  }
149 
151 
157  basic_socket_streambuf<Protocol, StreamSocketService,
158  Time, TimeTraits, TimerService>* connect(
159  const endpoint_type& endpoint)
160  {
161  init_buffers();
162 
164 
165  if (timer_state_ == timer_has_expired)
166  {
168  return 0;
169  }
170 
171  io_handler handler = { this };
173  endpoint, handler);
174 
176  this->get_service().get_io_service().reset();
177  do this->get_service().get_io_service().run_one();
178  while (ec_ == asio::error::would_block);
179 
180  return !ec_ ? this : 0;
181  }
182 
183 #if defined(GENERATING_DOCUMENTATION)
184 
193  template <typename T1, ..., typename TN>
195  T1 t1, ..., TN tn);
196 #elif defined(ASIO_HAS_VARIADIC_TEMPLATES)
197  template <typename... T>
198  basic_socket_streambuf<Protocol, StreamSocketService,
199  Time, TimeTraits, TimerService>* connect(T... x)
200  {
201  init_buffers();
203  typedef typename Protocol::resolver resolver_type;
204  typedef typename resolver_type::query resolver_query;
205  resolver_query query(x...);
206  resolve_and_connect(query);
207  return !ec_ ? this : 0;
208  }
209 #else
211 #endif
212 
214 
218  basic_socket_streambuf<Protocol, StreamSocketService,
219  Time, TimeTraits, TimerService>* close()
220  {
221  sync();
223  if (!ec_)
224  init_buffers();
225  return !ec_ ? this : 0;
226  }
227 
229 
233  const asio::error_code& puberror() const
234  {
235  return error();
236  }
237 
239 
243  time_type expires_at() const
244  {
245  return timer_service_
246  ? timer_service_->expires_at(timer_implementation_)
247  : time_type();
248  }
249 
251 
259  void expires_at(const time_type& expiry_time)
260  {
261  construct_timer();
262 
263  asio::error_code ec;
264  timer_service_->expires_at(timer_implementation_, expiry_time, ec);
265  asio::detail::throw_error(ec, "expires_at");
266 
267  start_timer();
268  }
269 
271 
274  duration_type expires_from_now() const
275  {
276  return traits_helper::subtract(expires_at(), traits_helper::now());
277  }
278 
280 
288  void expires_from_now(const duration_type& expiry_time)
289  {
290  construct_timer();
291 
292  asio::error_code ec;
293  timer_service_->expires_from_now(timer_implementation_, expiry_time, ec);
294  asio::detail::throw_error(ec, "expires_from_now");
295 
296  start_timer();
297  }
298 
299 protected:
300  int_type underflow()
301  {
302  if (gptr() == egptr())
303  {
304  if (timer_state_ == timer_has_expired)
305  {
307  return traits_type::eof();
308  }
309 
310  io_handler handler = { this };
311  this->get_service().async_receive(this->get_implementation(),
312  asio::buffer(asio::buffer(get_buffer_) + putback_max),
313  0, handler);
314 
316  this->get_service().get_io_service().reset();
317  do this->get_service().get_io_service().run_one();
318  while (ec_ == asio::error::would_block);
319  if (ec_)
320  return traits_type::eof();
321 
322  setg(&get_buffer_[0], &get_buffer_[0] + putback_max,
323  &get_buffer_[0] + putback_max + bytes_transferred_);
324  return traits_type::to_int_type(*gptr());
325  }
326  else
327  {
328  return traits_type::eof();
329  }
330  }
331 
332  int_type overflow(int_type c)
333  {
334  if (unbuffered_)
335  {
336  if (traits_type::eq_int_type(c, traits_type::eof()))
337  {
338  // Nothing to do.
339  return traits_type::not_eof(c);
340  }
341  else
342  {
343  if (timer_state_ == timer_has_expired)
344  {
346  return traits_type::eof();
347  }
348 
349  // Send the single character immediately.
350  char_type ch = traits_type::to_char_type(c);
351  io_handler handler = { this };
352  this->get_service().async_send(this->get_implementation(),
353  asio::buffer(&ch, sizeof(char_type)), 0, handler);
354 
356  this->get_service().get_io_service().reset();
357  do this->get_service().get_io_service().run_one();
358  while (ec_ == asio::error::would_block);
359  if (ec_)
360  return traits_type::eof();
361 
362  return c;
363  }
364  }
365  else
366  {
367  // Send all data in the output buffer.
369  asio::buffer(pbase(), pptr() - pbase());
370  while (asio::buffer_size(buffer) > 0)
371  {
372  if (timer_state_ == timer_has_expired)
373  {
375  return traits_type::eof();
376  }
377 
378  io_handler handler = { this };
379  this->get_service().async_send(this->get_implementation(),
380  asio::buffer(buffer), 0, handler);
381 
383  this->get_service().get_io_service().reset();
384  do this->get_service().get_io_service().run_one();
385  while (ec_ == asio::error::would_block);
386  if (ec_)
387  return traits_type::eof();
388 
389  buffer = buffer + bytes_transferred_;
390  }
391  setp(&put_buffer_[0], &put_buffer_[0] + put_buffer_.size());
392 
393  // If the new character is eof then our work here is done.
394  if (traits_type::eq_int_type(c, traits_type::eof()))
395  return traits_type::not_eof(c);
396 
397  // Add the new character to the output buffer.
398  *pptr() = traits_type::to_char_type(c);
399  pbump(1);
400  return c;
401  }
402  }
403 
404  int sync()
405  {
406  return overflow(traits_type::eof());
407  }
408 
409  std::streambuf* setbuf(char_type* s, std::streamsize n)
410  {
411  if (pptr() == pbase() && s == 0 && n == 0)
412  {
413  unbuffered_ = true;
414  setp(0, 0);
415  return this;
416  }
417 
418  return 0;
419  }
420 
422 
426  virtual const asio::error_code& error() const
427  {
428  return ec_;
429  }
430 
431 private:
432  void init_buffers()
433  {
434  setg(&get_buffer_[0],
435  &get_buffer_[0] + putback_max,
436  &get_buffer_[0] + putback_max);
437  if (unbuffered_)
438  setp(0, 0);
439  else
440  setp(&put_buffer_[0], &put_buffer_[0] + put_buffer_.size());
441  }
442 
443  template <typename ResolverQuery>
444  void resolve_and_connect(const ResolverQuery& query)
445  {
446  typedef typename Protocol::resolver resolver_type;
447  typedef typename resolver_type::iterator iterator_type;
448  resolver_type resolver(detail::socket_streambuf_base::io_service_);
449  iterator_type i = resolver.resolve(query, ec_);
450  if (!ec_)
451  {
452  iterator_type end;
454  while (ec_ && i != end)
455  {
457 
458  if (timer_state_ == timer_has_expired)
459  {
461  return;
462  }
463 
464  io_handler handler = { this };
466  *i, handler);
467 
469  this->get_service().get_io_service().reset();
470  do this->get_service().get_io_service().run_one();
471  while (ec_ == asio::error::would_block);
472 
473  ++i;
474  }
475  }
476  }
477 
478  struct io_handler;
479  friend struct io_handler;
480  struct io_handler
481  {
482  basic_socket_streambuf* this_;
483 
484  void operator()(const asio::error_code& ec,
485  std::size_t bytes_transferred = 0)
486  {
487  this_->ec_ = ec;
488  this_->bytes_transferred_ = bytes_transferred;
489  }
490  };
491 
492  struct timer_handler;
493  friend struct timer_handler;
494  struct timer_handler
495  {
496  basic_socket_streambuf* this_;
497 
498  void operator()(const asio::error_code&)
499  {
500  time_type now = traits_helper::now();
501 
502  time_type expiry_time = this_->timer_service_->expires_at(
503  this_->timer_implementation_);
504 
505  if (traits_helper::less_than(now, expiry_time))
506  {
507  this_->timer_state_ = timer_is_pending;
508  this_->timer_service_->async_wait(this_->timer_implementation_, *this);
509  }
510  else
511  {
512  this_->timer_state_ = timer_has_expired;
513  asio::error_code ec;
514  this_->basic_socket<Protocol, StreamSocketService>::close(ec);
515  }
516  }
517  };
518 
519  void construct_timer()
520  {
521  if (timer_service_ == 0)
522  {
523  TimerService& timer_service = use_service<TimerService>(
525  timer_service.construct(timer_implementation_);
526  timer_service_ = &timer_service;
527  }
528  }
529 
530  void destroy_timer()
531  {
532  if (timer_service_)
533  timer_service_->destroy(timer_implementation_);
534  }
535 
536  void start_timer()
537  {
538  if (timer_state_ != timer_is_pending)
539  {
540  timer_handler handler = { this };
541  handler(asio::error_code());
542  }
543  }
544 
545  enum { putback_max = 8 };
546  enum { buffer_size = 512 };
549  bool unbuffered_;
550  asio::error_code ec_;
551  std::size_t bytes_transferred_;
552  TimerService* timer_service_;
553  typename TimerService::implementation_type timer_implementation_;
554  enum state { no_timer, timer_is_pending, timer_has_expired } timer_state_;
555 };
556 
557 } // namespace asio
558 
560 
561 #if !defined(ASIO_HAS_VARIADIC_TEMPLATES)
562 # undef ASIO_PRIVATE_CONNECT_DEF
563 #endif // !defined(ASIO_HAS_VARIADIC_TEMPLATES)
564 
565 #endif // !defined(ASIO_NO_IOSTREAM)
566 
567 #endif // ASIO_BASIC_SOCKET_STREAMBUF_HPP
const asio::error_code & puberror() const
Get the last error associated with the stream buffer.
void expires_at(const time_type &expiry_time)
Set the stream buffer&#39;s expiry time as an absolute time.
Operation cancelled.
Definition: error.hpp:161
void throw_error(const asio::error_code &err)
Definition: throw_error.hpp:31
basic_streambuf streambuf
Typedef for the typical usage of basic_streambuf.
Definition: streambuf.hpp:27
Provides core I/O functionality.
Definition: io_service.hpp:184
Holds a buffer that cannot be modified.
Definition: buffer.hpp:211
SocketService & s
Definition: connect.hpp:521
Protocol::endpoint endpoint_type
The endpoint type.
traits_helper::duration_type duration_type
Default service implementation for a stream socket.
virtual ~basic_socket_streambuf()
Destructor flushes buffered data.
mutable_buffers_1 buffer(const mutable_buffer &b)
Create a new modifiable buffer from an existing buffer.
Definition: buffer.hpp:706
Iterator connect(basic_socket< Protocol, SocketService > &s, Iterator begin)
Establishes a socket connection by trying each endpoint in a sequence.
Definition: connect.hpp:44
The socket is marked non-blocking and the requested operation would block.
Definition: error.hpp:180
traits_helper::time_type time_type
End of file or stream.
Definition: error.hpp:217
std::size_t buffer_size(const mutable_buffer &b)
Get the number of bytes in a modifiable buffer.
Definition: buffer.hpp:357
Host not found (authoritative).
Definition: error.hpp:186
void expires_from_now(const duration_type &expiry_time)
Set the stream buffer&#39;s expiry time relative to now.
basic_socket_streambuf< Protocol, StreamSocketService, Time, TimeTraits, TimerService > * connect(const endpoint_type &endpoint)
Establish a connection.
Class to represent an error code value.
Definition: error_code.hpp:80
#define ASIO_VARIADIC_GENERATE(m)
#define ASIO_PRIVATE_CONNECT_DEF(n)
basic_socket_streambuf()
Construct a basic_socket_streambuf without establishing a connection.
void close()
Close the socket.
time_type expires_at() const
Get the stream buffer&#39;s expiry time as an absolute time.
Provides socket functionality.
SocketService Iterator Iterator end
Definition: connect.hpp:592
Iostream streambuf for a socket.
duration_type expires_from_now() const
Get the stream buffer&#39;s expiry time relative to now.
std::streambuf * setbuf(char_type *s, std::streamsize n)
virtual const asio::error_code & error() const
Get the last error associated with the stream buffer.
basic_socket_streambuf< Protocol, StreamSocketService, Time, TimeTraits, TimerService > * close()
Close the connection.