MIRA
SyncTimedRead.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2012 by
3  * MetraLabs GmbH (MLAB), GERMANY
4  * and
5  * Neuroinformatics and Cognitive Robotics Labs (NICR) at TU Ilmenau, GERMANY
6  * All rights reserved.
7  *
8  * Contact: info@mira-project.org
9  *
10  * Commercial Usage:
11  * Licensees holding valid commercial licenses may use this file in
12  * accordance with the commercial license agreement provided with the
13  * software or, alternatively, in accordance with the terms contained in
14  * a written agreement between you and MLAB or NICR.
15  *
16  * GNU General Public License Usage:
17  * Alternatively, this file may be used under the terms of the GNU
18  * General Public License version 3.0 as published by the Free Software
19  * Foundation and appearing in the file LICENSE.GPL3 included in the
20  * packaging of this file. Please review the following information to
21  * ensure the GNU General Public License version 3.0 requirements will be
22  * met: http://www.gnu.org/copyleft/gpl.html.
23  * Alternatively you may (at your option) use any later version of the GNU
24  * General Public License if such license has been publicly approved by
25  * MLAB and NICR (or its successors, if any).
26  *
27  * IN NO EVENT SHALL "MLAB" OR "NICR" BE LIABLE TO ANY PARTY FOR DIRECT,
28  * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
29  * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF "MLAB" OR
30  * "NICR" HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  * "MLAB" AND "NICR" SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
33  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
34  * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
35  * ON AN "AS IS" BASIS, AND "MLAB" AND "NICR" HAVE NO OBLIGATION TO
36  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR MODIFICATIONS.
37  */
38 
47 #ifndef _MIRA_SYNCTIMEDREAD_H_
48 #define _MIRA_SYNCTIMEDREAD_H_
49 
50 #ifndef Q_MOC_RUN
51 #include <boost/asio/deadline_timer.hpp>
52 #include <boost/optional.hpp>
53 #if BOOST_VERSION >= 107000
54 # include <boost/asio/io_context.hpp>
55 #endif
56 #endif
57 
58 #include <utils/Bind.h>
59 #include <utils/Time.h>
60 #include <error/Exceptions.h>
61 
62 namespace boost { namespace asio {
63 
65 
67 
68 namespace Private {
69 
70 inline void setTimerResult(optional<system::error_code>* codeStorage,
71  system::error_code code)
72 {
73  // If we got a boost::asio::error::operation_aborted, ignore it.
74  if (code == error::operation_aborted)
75  return;
76 
77  codeStorage->reset(code);
78 }
79 
80 inline void setResult(optional<system::error_code>* codeStorage,
81  std::size_t* bytesReceivedStorage,
82  system::error_code code, std::size_t bytesReceived)
83 {
84  // If we got a boost::asio::error::operation_aborted, ignore it.
85  if (code == error::operation_aborted)
86  return;
87 
88  codeStorage->reset(code);
89  *bytesReceivedStorage = bytesReceived;
90 }
91 
92 }
94 
96 
106 template<typename SyncReadStream, typename MutableBufferSequence>
107 std::size_t read_some(SyncReadStream& s, const MutableBufferSequence& buffers,
108  mira::Duration timeout)
109 {
110  system::error_code ec;
111  std::size_t bytesRead = read_some(s, buffers, timeout, ec);
112  detail::throw_error(ec);
113  return bytesRead;
114 }
115 
122 template<typename SyncReadStream, typename MutableBufferSequence>
123 std::size_t read_some(SyncReadStream& s, const MutableBufferSequence& buffers,
124  mira::Duration timeout, system::error_code& ec)
125 {
126  ec = boost::system::error_code();
127  optional<system::error_code> timerResult;
128  optional<system::error_code> readResult;
129  std::size_t bytesRead = 0;
130 
131 #if BOOST_VERSION >= 107000
132  boost::asio::io_context& s_io_service = static_cast<boost::asio::io_context&>(s.get_executor().context());
133 #else
134  auto& s_io_service = s.get_io_service();
135 #endif
136 
137  deadline_timer timer(s_io_service);
138 
139  timer.expires_from_now(timeout);
140 #if BOOST_VERSION >= 107400
141  using namespace mira::placeholders;
142 #endif
143  timer.async_wait(bind(&Private::setTimerResult, &timerResult, _1));
144 
145  s.async_read_some(buffers, bind(&Private::setResult,
146  &readResult, &bytesRead, _1, _2));
147 
148  s_io_service.reset();
149 
150  // For more details on the following code, please look here:
151  // http://stackoverflow.com/questions/10858719/cancel-async-read-due-to-timeout
152 
153  // It is important to use a loop here, to ensure, that all handlers are
154  // remove from the io_service, before leaving this method. Otherwise a
155  // subsequent call of read_some will return immediately caused by still
156  // outstanding handlers.
157  // The io_service::reset() method only allows the io_service to resume
158  // running from a stopped state, it does not remove any handlers already
159  // queued into the io_service.
160 
161  while (s_io_service.run_one())
162  {
163  if (readResult)
164  {
165  // Data received, so cancel the timer.
166  // This will result in a call of the handler Private::setTimerResult
167  // with boost::asio::error::operation_aborted as the error.
168  timer.cancel();
169  ec = readResult.get();
170  } else
171  if (timerResult)
172  {
173  // Timeout occurred, so cancel the read operation. This will result
174  // in a call of the handler Private::setResult with the error code
175  // boost::asio::error::operation_aborted.
176  s.cancel();
177  ec = system::error_code(system::errc::timed_out,
178  system::generic_category());
179  //return bytesRead;
180  }
181  }
182 
183  // Reset service, guaranteeing it is in a good state for subsequential runs.
184  s_io_service.reset();
185 
186  return bytesRead;
187 }
188 
190 
191 }}
192 
193 #endif
Definition: SyncTimedRead.h:62
Time and Duration wrapper class.
std::size_t read_some(SyncReadStream &s, const MutableBufferSequence &buffers, mira::Duration timeout)
Read some data from the specified stream &#39;s&#39; into the given buffer &#39;buffers&#39;.
Definition: SyncTimedRead.h:107
Commonly used exception classes.
Use this class to represent time durations.
Definition: Time.h:106
Wrapper for boost/bind.