1 //
2 // impl/read.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_IMPL_READ_HPP
12 #define ASIO_IMPL_READ_HPP
13 
14 
15 #include <algorithm>
16 #include "asio/buffer.hpp"
17 #include "asio/completion_condition.hpp"
18 #include "asio/detail/array_fwd.hpp"
19 #include "asio/detail/base_from_completion_cond.hpp"
20 #include "asio/detail/bind_handler.hpp"
21 #include "asio/detail/consuming_buffers.hpp"
22 #include "asio/detail/dependent_type.hpp"
23 #include "asio/detail/handler_alloc_helpers.hpp"
24 #include "asio/detail/handler_cont_helpers.hpp"
25 #include "asio/detail/handler_invoke_helpers.hpp"
26 #include "asio/detail/handler_type_requirements.hpp"
27 #include "asio/detail/throw_error.hpp"
28 #include "asio/error.hpp"
29 
30 #include "asio/detail/push_options.hpp"
31 
32 namespace asio {
33 
34 template <typename SyncReadStream, typename MutableBufferSequence,
35     typename CompletionCondition>
read(SyncReadStream & s,const MutableBufferSequence & buffers,CompletionCondition completion_condition,asio::error_code & ec)36 std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,
37     CompletionCondition completion_condition, asio::error_code& ec)
38 {
39   ec = asio::error_code();
40   asio::detail::consuming_buffers<
41     mutable_buffer, MutableBufferSequence> tmp(buffers);
42   std::size_t total_transferred = 0;
43   tmp.prepare(detail::adapt_completion_condition_result(
44         completion_condition(ec, total_transferred)));
45   while (tmp.begin() != tmp.end())
46   {
47     std::size_t bytes_transferred = s.read_some(tmp, ec);
48     tmp.consume(bytes_transferred);
49     total_transferred += bytes_transferred;
50     tmp.prepare(detail::adapt_completion_condition_result(
51           completion_condition(ec, total_transferred)));
52   }
53   return total_transferred;
54 }
55 
56 template <typename SyncReadStream, typename MutableBufferSequence>
read(SyncReadStream & s,const MutableBufferSequence & buffers)57 inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers)
58 {
59   asio::error_code ec;
60   std::size_t bytes_transferred = read(s, buffers, transfer_all(), ec);
61   asio::detail::throw_error(ec, "read");
62   return bytes_transferred;
63 }
64 
65 template <typename SyncReadStream, typename MutableBufferSequence>
read(SyncReadStream & s,const MutableBufferSequence & buffers,asio::error_code & ec)66 inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,
67     asio::error_code& ec)
68 {
69   return read(s, buffers, transfer_all(), ec);
70 }
71 
72 template <typename SyncReadStream, typename MutableBufferSequence,
73     typename CompletionCondition>
read(SyncReadStream & s,const MutableBufferSequence & buffers,CompletionCondition completion_condition)74 inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,
75     CompletionCondition completion_condition)
76 {
77   asio::error_code ec;
78   std::size_t bytes_transferred = read(s, buffers, completion_condition, ec);
79   asio::detail::throw_error(ec, "read");
80   return bytes_transferred;
81 }
82 
83 
84 namespace detail
85 {
86   template <typename AsyncReadStream, typename MutableBufferSequence,
87       typename CompletionCondition, typename ReadHandler>
88   class read_op
89     : detail::base_from_completion_cond<CompletionCondition>
90   {
91   public:
read_op(AsyncReadStream & stream,const MutableBufferSequence & buffers,CompletionCondition completion_condition,ReadHandler & handler)92     read_op(AsyncReadStream& stream, const MutableBufferSequence& buffers,
93         CompletionCondition completion_condition, ReadHandler& handler)
94       : detail::base_from_completion_cond<
95           CompletionCondition>(completion_condition),
96         stream_(stream),
97         buffers_(buffers),
98         start_(0),
99         total_transferred_(0),
100         handler_(ASIO_MOVE_CAST(ReadHandler)(handler))
101     {
102     }
103 
read_op(const read_op & other)104     read_op(const read_op& other)
105       : detail::base_from_completion_cond<CompletionCondition>(other),
106         stream_(other.stream_),
107         buffers_(other.buffers_),
108         start_(other.start_),
109         total_transferred_(other.total_transferred_),
110         handler_(other.handler_)
111     {
112     }
113 
read_op(read_op && other)114     read_op(read_op&& other)
115       : detail::base_from_completion_cond<CompletionCondition>(other),
116         stream_(other.stream_),
117         buffers_(other.buffers_),
118         start_(other.start_),
119         total_transferred_(other.total_transferred_),
120         handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))
121     {
122     }
123 
operator ()(const asio::error_code & ec,std::size_t bytes_transferred,int start=0)124     void operator()(const asio::error_code& ec,
125         std::size_t bytes_transferred, int start = 0)
126     {
127       switch (start_ = start)
128       {
129         case 1:
130         buffers_.prepare(this->check_for_completion(ec, total_transferred_));
131         for (;;)
132         {
133           stream_.async_read_some(buffers_,
134               ASIO_MOVE_CAST(read_op)(*this));
135           return; default:
136           total_transferred_ += bytes_transferred;
137           buffers_.consume(bytes_transferred);
138           buffers_.prepare(this->check_for_completion(ec, total_transferred_));
139           if ((!ec && bytes_transferred == 0)
140               || buffers_.begin() == buffers_.end())
141             break;
142         }
143 
144         handler_(ec, static_cast<const std::size_t&>(total_transferred_));
145       }
146     }
147 
148   //private:
149     AsyncReadStream& stream_;
150     asio::detail::consuming_buffers<
151       mutable_buffer, MutableBufferSequence> buffers_;
152     int start_;
153     std::size_t total_transferred_;
154     ReadHandler handler_;
155   };
156 
157   template <typename AsyncReadStream,
158       typename CompletionCondition, typename ReadHandler>
159   class read_op<AsyncReadStream, asio::mutable_buffers_1,
160       CompletionCondition, ReadHandler>
161     : detail::base_from_completion_cond<CompletionCondition>
162   {
163   public:
read_op(AsyncReadStream & stream,const asio::mutable_buffers_1 & buffers,CompletionCondition completion_condition,ReadHandler & handler)164     read_op(AsyncReadStream& stream,
165         const asio::mutable_buffers_1& buffers,
166         CompletionCondition completion_condition, ReadHandler& handler)
167       : detail::base_from_completion_cond<
168           CompletionCondition>(completion_condition),
169         stream_(stream),
170         buffer_(buffers),
171         start_(0),
172         total_transferred_(0),
173         handler_(ASIO_MOVE_CAST(ReadHandler)(handler))
174     {
175     }
176 
read_op(const read_op & other)177     read_op(const read_op& other)
178       : detail::base_from_completion_cond<CompletionCondition>(other),
179         stream_(other.stream_),
180         buffer_(other.buffer_),
181         start_(other.start_),
182         total_transferred_(other.total_transferred_),
183         handler_(other.handler_)
184     {
185     }
186 
read_op(read_op && other)187     read_op(read_op&& other)
188       : detail::base_from_completion_cond<CompletionCondition>(other),
189         stream_(other.stream_),
190         buffer_(other.buffer_),
191         start_(other.start_),
192         total_transferred_(other.total_transferred_),
193         handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))
194     {
195     }
196 
operator ()(const asio::error_code & ec,std::size_t bytes_transferred,int start=0)197     void operator()(const asio::error_code& ec,
198         std::size_t bytes_transferred, int start = 0)
199     {
200       std::size_t n = 0;
201       switch (start_ = start)
202       {
203         case 1:
204         n = this->check_for_completion(ec, total_transferred_);
205         for (;;)
206         {
207           stream_.async_read_some(
208               asio::buffer(buffer_ + total_transferred_, n),
209               ASIO_MOVE_CAST(read_op)(*this));
210           return; default:
211           total_transferred_ += bytes_transferred;
212           if ((!ec && bytes_transferred == 0)
213               || (n = this->check_for_completion(ec, total_transferred_)) == 0
214               || total_transferred_ == asio::buffer_size(buffer_))
215             break;
216         }
217 
218         handler_(ec, static_cast<const std::size_t&>(total_transferred_));
219       }
220     }
221 
222   //private:
223     AsyncReadStream& stream_;
224     asio::mutable_buffer buffer_;
225     int start_;
226     std::size_t total_transferred_;
227     ReadHandler handler_;
228   };
229 
230   template <typename AsyncReadStream, typename Elem,
231       typename CompletionCondition, typename ReadHandler>
232   class read_op<AsyncReadStream, boost::array<Elem, 2>,
233       CompletionCondition, ReadHandler>
234     : detail::base_from_completion_cond<CompletionCondition>
235   {
236   public:
read_op(AsyncReadStream & stream,const boost::array<Elem,2> & buffers,CompletionCondition completion_condition,ReadHandler & handler)237     read_op(AsyncReadStream& stream, const boost::array<Elem, 2>& buffers,
238         CompletionCondition completion_condition, ReadHandler& handler)
239       : detail::base_from_completion_cond<
240           CompletionCondition>(completion_condition),
241         stream_(stream),
242         buffers_(buffers),
243         start_(0),
244         total_transferred_(0),
245         handler_(ASIO_MOVE_CAST(ReadHandler)(handler))
246     {
247     }
248 
read_op(const read_op & other)249     read_op(const read_op& other)
250       : detail::base_from_completion_cond<CompletionCondition>(other),
251         stream_(other.stream_),
252         buffers_(other.buffers_),
253         start_(other.start_),
254         total_transferred_(other.total_transferred_),
255         handler_(other.handler_)
256     {
257     }
258 
read_op(read_op && other)259     read_op(read_op&& other)
260       : detail::base_from_completion_cond<CompletionCondition>(other),
261         stream_(other.stream_),
262         buffers_(other.buffers_),
263         start_(other.start_),
264         total_transferred_(other.total_transferred_),
265         handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))
266     {
267     }
268 
operator ()(const asio::error_code & ec,std::size_t bytes_transferred,int start=0)269     void operator()(const asio::error_code& ec,
270         std::size_t bytes_transferred, int start = 0)
271     {
272       typename asio::detail::dependent_type<Elem,
273           boost::array<asio::mutable_buffer, 2> >::type bufs = {{
274         asio::mutable_buffer(buffers_[0]),
275         asio::mutable_buffer(buffers_[1]) }};
276       std::size_t buffer_size0 = asio::buffer_size(bufs[0]);
277       std::size_t buffer_size1 = asio::buffer_size(bufs[1]);
278       std::size_t n = 0;
279       switch (start_ = start)
280       {
281         case 1:
282         n = this->check_for_completion(ec, total_transferred_);
283         for (;;)
284         {
285           bufs[0] = asio::buffer(bufs[0] + total_transferred_, n);
286           bufs[1] = asio::buffer(
287               bufs[1] + (total_transferred_ < buffer_size0
288                 ? 0 : total_transferred_ - buffer_size0),
289               n - asio::buffer_size(bufs[0]));
290           stream_.async_read_some(bufs, ASIO_MOVE_CAST(read_op)(*this));
291           return; default:
292           total_transferred_ += bytes_transferred;
293           if ((!ec && bytes_transferred == 0)
294               || (n = this->check_for_completion(ec, total_transferred_)) == 0
295               || total_transferred_ == buffer_size0 + buffer_size1)
296             break;
297         }
298 
299         handler_(ec, static_cast<const std::size_t&>(total_transferred_));
300       }
301     }
302 
303   //private:
304     AsyncReadStream& stream_;
305     boost::array<Elem, 2> buffers_;
306     int start_;
307     std::size_t total_transferred_;
308     ReadHandler handler_;
309   };
310 
311 
312   template <typename AsyncReadStream, typename Elem,
313       typename CompletionCondition, typename ReadHandler>
314   class read_op<AsyncReadStream, std::array<Elem, 2>,
315       CompletionCondition, ReadHandler>
316     : detail::base_from_completion_cond<CompletionCondition>
317   {
318   public:
read_op(AsyncReadStream & stream,const std::array<Elem,2> & buffers,CompletionCondition completion_condition,ReadHandler & handler)319     read_op(AsyncReadStream& stream, const std::array<Elem, 2>& buffers,
320         CompletionCondition completion_condition, ReadHandler& handler)
321       : detail::base_from_completion_cond<
322           CompletionCondition>(completion_condition),
323         stream_(stream),
324         buffers_(buffers),
325         start_(0),
326         total_transferred_(0),
327         handler_(ASIO_MOVE_CAST(ReadHandler)(handler))
328     {
329     }
330 
read_op(const read_op & other)331     read_op(const read_op& other)
332       : detail::base_from_completion_cond<CompletionCondition>(other),
333         stream_(other.stream_),
334         buffers_(other.buffers_),
335         start_(other.start_),
336         total_transferred_(other.total_transferred_),
337         handler_(other.handler_)
338     {
339     }
340 
read_op(read_op && other)341     read_op(read_op&& other)
342       : detail::base_from_completion_cond<CompletionCondition>(other),
343         stream_(other.stream_),
344         buffers_(other.buffers_),
345         start_(other.start_),
346         total_transferred_(other.total_transferred_),
347         handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))
348     {
349     }
350 
operator ()(const asio::error_code & ec,std::size_t bytes_transferred,int start=0)351     void operator()(const asio::error_code& ec,
352         std::size_t bytes_transferred, int start = 0)
353     {
354       typename asio::detail::dependent_type<Elem,
355           std::array<asio::mutable_buffer, 2> >::type bufs = {{
356         asio::mutable_buffer(buffers_[0]),
357         asio::mutable_buffer(buffers_[1]) }};
358       std::size_t buffer_size0 = asio::buffer_size(bufs[0]);
359       std::size_t buffer_size1 = asio::buffer_size(bufs[1]);
360       std::size_t n = 0;
361       switch (start_ = start)
362       {
363         case 1:
364         n = this->check_for_completion(ec, total_transferred_);
365         for (;;)
366         {
367           bufs[0] = asio::buffer(bufs[0] + total_transferred_, n);
368           bufs[1] = asio::buffer(
369               bufs[1] + (total_transferred_ < buffer_size0
370                 ? 0 : total_transferred_ - buffer_size0),
371               n - asio::buffer_size(bufs[0]));
372           stream_.async_read_some(bufs, ASIO_MOVE_CAST(read_op)(*this));
373           return; default:
374           total_transferred_ += bytes_transferred;
375           if ((!ec && bytes_transferred == 0)
376               || (n = this->check_for_completion(ec, total_transferred_)) == 0
377               || total_transferred_ == buffer_size0 + buffer_size1)
378             break;
379         }
380 
381         handler_(ec, static_cast<const std::size_t&>(total_transferred_));
382       }
383     }
384 
385   //private:
386     AsyncReadStream& stream_;
387     std::array<Elem, 2> buffers_;
388     int start_;
389     std::size_t total_transferred_;
390     ReadHandler handler_;
391   };
392 
393 
394   template <typename AsyncReadStream, typename MutableBufferSequence,
395       typename CompletionCondition, typename ReadHandler>
asio_handler_allocate(std::size_t size,read_op<AsyncReadStream,MutableBufferSequence,CompletionCondition,ReadHandler> * this_handler)396   inline void* asio_handler_allocate(std::size_t size,
397       read_op<AsyncReadStream, MutableBufferSequence,
398         CompletionCondition, ReadHandler>* this_handler)
399   {
400     return asio_handler_alloc_helpers::allocate(
401         size, this_handler->handler_);
402   }
403 
404   template <typename AsyncReadStream, typename MutableBufferSequence,
405       typename CompletionCondition, typename ReadHandler>
asio_handler_deallocate(void * pointer,std::size_t size,read_op<AsyncReadStream,MutableBufferSequence,CompletionCondition,ReadHandler> * this_handler)406   inline void asio_handler_deallocate(void* pointer, std::size_t size,
407       read_op<AsyncReadStream, MutableBufferSequence,
408         CompletionCondition, ReadHandler>* this_handler)
409   {
410     asio_handler_alloc_helpers::deallocate(
411         pointer, size, this_handler->handler_);
412   }
413 
414   template <typename AsyncReadStream, typename MutableBufferSequence,
415       typename CompletionCondition, typename ReadHandler>
asio_handler_is_continuation(read_op<AsyncReadStream,MutableBufferSequence,CompletionCondition,ReadHandler> * this_handler)416   inline bool asio_handler_is_continuation(
417       read_op<AsyncReadStream, MutableBufferSequence,
418         CompletionCondition, ReadHandler>* this_handler)
419   {
420     return this_handler->start_ == 0 ? true
421       : asio_handler_cont_helpers::is_continuation(
422           this_handler->handler_);
423   }
424 
425   template <typename Function, typename AsyncReadStream,
426       typename MutableBufferSequence, typename CompletionCondition,
427       typename ReadHandler>
asio_handler_invoke(Function & function,read_op<AsyncReadStream,MutableBufferSequence,CompletionCondition,ReadHandler> * this_handler)428   inline void asio_handler_invoke(Function& function,
429       read_op<AsyncReadStream, MutableBufferSequence,
430         CompletionCondition, ReadHandler>* this_handler)
431   {
432     asio_handler_invoke_helpers::invoke(
433         function, this_handler->handler_);
434   }
435 
436   template <typename Function, typename AsyncReadStream,
437       typename MutableBufferSequence, typename CompletionCondition,
438       typename ReadHandler>
asio_handler_invoke(const Function & function,read_op<AsyncReadStream,MutableBufferSequence,CompletionCondition,ReadHandler> * this_handler)439   inline void asio_handler_invoke(const Function& function,
440       read_op<AsyncReadStream, MutableBufferSequence,
441         CompletionCondition, ReadHandler>* this_handler)
442   {
443     asio_handler_invoke_helpers::invoke(
444         function, this_handler->handler_);
445   }
446 } // namespace detail
447 
448 template <typename AsyncReadStream, typename MutableBufferSequence,
449     typename CompletionCondition, typename ReadHandler>
ASIO_INITFN_RESULT_TYPE(ReadHandler,void (asio::error_code,std::size_t))450 inline ASIO_INITFN_RESULT_TYPE(ReadHandler,
451     void (asio::error_code, std::size_t))
452 async_read(AsyncReadStream& s, const MutableBufferSequence& buffers,
453     CompletionCondition completion_condition,
454     ASIO_MOVE_ARG(ReadHandler) handler)
455 {
456   // If you get an error on the following line it means that your handler does
457   // not meet the documented type requirements for a ReadHandler.
458   ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
459 
460   detail::async_result_init<
461     ReadHandler, void (asio::error_code, std::size_t)> init(
462       ASIO_MOVE_CAST(ReadHandler)(handler));
463 
464   detail::read_op<AsyncReadStream, MutableBufferSequence,
465     CompletionCondition, ASIO_HANDLER_TYPE(
466       ReadHandler, void (asio::error_code, std::size_t))>(
467         s, buffers, completion_condition, init.handler)(
468           asio::error_code(), 0, 1);
469 
470   return init.result.get();
471 }
472 
473 template <typename AsyncReadStream, typename MutableBufferSequence,
474     typename ReadHandler>
ASIO_INITFN_RESULT_TYPE(ReadHandler,void (asio::error_code,std::size_t))475 inline ASIO_INITFN_RESULT_TYPE(ReadHandler,
476     void (asio::error_code, std::size_t))
477 async_read(AsyncReadStream& s, const MutableBufferSequence& buffers,
478     ASIO_MOVE_ARG(ReadHandler) handler)
479 {
480   // If you get an error on the following line it means that your handler does
481   // not meet the documented type requirements for a ReadHandler.
482   ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
483 
484   detail::async_result_init<
485     ReadHandler, void (asio::error_code, std::size_t)> init(
486       ASIO_MOVE_CAST(ReadHandler)(handler));
487 
488   detail::read_op<AsyncReadStream, MutableBufferSequence,
489     detail::transfer_all_t, ASIO_HANDLER_TYPE(
490       ReadHandler, void (asio::error_code, std::size_t))>(
491         s, buffers, transfer_all(), init.handler)(
492           asio::error_code(), 0, 1);
493 
494   return init.result.get();
495 }
496 
497 
498 } // namespace asio
499 
500 #include "asio/detail/pop_options.hpp"
501 
502 #endif // ASIO_IMPL_READ_HPP
503