All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Pages
async-socket-transport.hpp
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
22 #ifndef NDN_ASYNC_SOCKET_TRANSPORT_HPP
23 #define NDN_ASYNC_SOCKET_TRANSPORT_HPP
24 
25 #include <stdexcept>
26 #include <boost/bind.hpp>
27 #include <boost/asio.hpp>
28 #include <boost/enable_shared_from_this.hpp>
29 #include <ndn-cpp/transport/transport.hpp>
30 #include "../c/encoding/element-reader.h"
31 #include "../encoding/element-listener.hpp"
32 #include "../util/dynamic-uint8-vector.hpp"
33 
34 namespace ndn {
35 
44 template<class AsioProtocol> class AsyncSocketTransport {
45 public:
52  AsyncSocketTransport(boost::asio::io_service& ioService)
53  : impl_(new Impl(ioService))
54  {
55  }
56 
68  void
69  connect
70  (const typename AsioProtocol::endpoint& endPoint,
71  ElementListener& elementListener, const Transport::OnConnected& onConnected)
72  {
73  impl_->connect(endPoint, elementListener, onConnected);
74  }
75 
83  void
84  send(const uint8_t *data, size_t dataLength)
85  {
86  impl_->send(data, dataLength);
87  }
88 
89  bool
90  getIsConnected()
91  {
92  return impl_->getIsConnected();
93  }
94 
98  void
100  {
101  impl_->close();
102  }
103 
104 private:
110  class Impl : public boost::enable_shared_from_this<Impl> {
111  public:
112  Impl(boost::asio::io_service& ioService)
113  : ioService_(ioService), socket_(new typename AsioProtocol::socket(ioService)),
114  elementBuffer_(new DynamicUInt8Vector(1000)), isConnected_(false)
115  {
116  ndn_ElementReader_initialize(&elementReader_, 0, elementBuffer_.get());
117  }
118 
129  void
130  connect
131  (const typename AsioProtocol::endpoint& endPoint,
132  ElementListener& elementListener, const Transport::OnConnected& onConnected)
133  {
134  close();
135 
136  ndn_ElementReader_reset(&elementReader_, &elementListener);
137 
138  socket_->async_connect
139  (endPoint,
140  boost::bind(&AsyncSocketTransport::Impl::connectHandler,
141  this->shared_from_this(), _1, onConnected));
142  }
143 
149  void
150  send(const uint8_t *data, size_t dataLength)
151  {
152  if (!isConnected_)
153  throw std::runtime_error
154  ("AsyncSocketTransport.send: The socket is not connected");
155 
156  // Assume that this is called from a dispatch so that we are already in the
157  // ioService_ thread. Just do a blocking write.
158  boost::system::error_code errorCode;
159  boost::asio::write
160  (*socket_, boost::asio::buffer(data, dataLength), errorCode);
161  if (errorCode != boost::system::errc::success)
162  throw std::runtime_error("AsyncSocketTransport.send: Error in write");
163  }
164 
165  bool
166  getIsConnected()
167  {
168  return isConnected_;
169  }
170 
174  void
175  close()
176  {
177  try {
178  socket_->close();
179  }
180  catch (...) {
181  // Ignore any exceptions.
182  }
183 
184  isConnected_ = false;
185  }
186 
187  private:
191  void
192  connectHandler
193  (const boost::system::error_code& errorCode,
194  const Transport::OnConnected& onConnected)
195  {
196  if (errorCode != boost::system::errc::success)
197  // TODO: How to report errors to the application?
198  throw std::runtime_error("AsyncSocketTransport: Error in async_connect");
199 
200  isConnected_ = true;
201  onConnected();
202 
203  socket_->async_receive
204  (boost::asio::buffer(receiveBuffer_, sizeof(receiveBuffer_)), 0,
205  boost::bind(&AsyncSocketTransport::Impl::readHandler,
206  this->shared_from_this(), _1, _2));
207  }
208 
213  void
214  readHandler(const boost::system::error_code& errorCode, size_t nBytesReceived)
215  {
216  if (errorCode != boost::system::errc::success) {
217  if (errorCode == boost::system::errc::operation_canceled)
218  // Assume the socket has been closed. Do nothing.
219  return;
220 
221  close();
222  // TODO: How to report errors to the application?
223  throw std::runtime_error("AsyncSocketTransport: Error in async_receive");
224  }
225 
226  ndn_Error error;
227  if ((error = ndn_ElementReader_onReceivedData
228  (&elementReader_, receiveBuffer_, nBytesReceived)))
229  throw std::runtime_error(ndn_getErrorString(error));
230 
231  // Request another async receive to loop back to here.
232  if (socket_->is_open())
233  socket_->async_receive
234  (boost::asio::buffer(receiveBuffer_, sizeof(receiveBuffer_)), 0,
235  boost::bind(&AsyncSocketTransport::Impl::readHandler,
236  this->shared_from_this(), _1, _2));
237  }
238 
239  boost::asio::io_service& ioService_;
240  boost::shared_ptr<typename AsioProtocol::socket> socket_;
241  uint8_t receiveBuffer_[MAX_NDN_PACKET_SIZE];
242  boost::shared_ptr<DynamicUInt8Vector> elementBuffer_;
243  ndn_ElementReader elementReader_;
244  bool isConnected_;
245  };
246 
247  boost::shared_ptr<Impl> impl_;
248 };
249 
250 }
251 
252 #endif
AsyncSocketTransport is a helper template class for AsyncTcpTransport and AsyncUnixTransport to imple...
Definition: async-socket-transport.hpp:44
An ElementListener extends an ndn_ElementListener struct to proved an abstract virtual onReceivedElem...
Definition: element-listener.hpp:33
void connect(const typename AsioProtocol::endpoint &endPoint, ElementListener &elementListener, const Transport::OnConnected &onConnected)
Connect according to the info in connectionInfo, and use elementListener.
Definition: async-socket-transport.hpp:70
void close()
Close the connection to the host.
Definition: async-socket-transport.hpp:99
void send(const uint8_t *data, size_t dataLength)
Send data to the host.
Definition: async-socket-transport.hpp:84
AsyncSocketTransport(boost::asio::io_service &ioService)
Create an AsyncSocketTransport in the unconnected state.
Definition: async-socket-transport.hpp:52
A DynamicUInt8Vector extends ndn_DynamicUInt8Array to hold a shared_ptr<vector<uint8_t> > for use wit...
Definition: dynamic-uint8-vector.hpp:37
A ndn_ElementReader lets you call ndn_ElementReader_onReceivedData multiple times which uses an ndn_T...
Definition: element-reader-types.h:59