NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.0: NDN, CCN, CCNx, content centric networks
API Documentation
tcp-channel.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
26 #include "tcp-channel.hpp"
27 #include "tcp-face.hpp"
28 #include "core/global-io.hpp"
29 
30 namespace nfd {
31 
32 NFD_LOG_INIT("TcpChannel");
33 
34 using namespace boost::asio;
35 
37  : m_localEndpoint(localEndpoint)
38  , m_acceptor(getGlobalIoService())
39  , m_acceptSocket(getGlobalIoService())
40 {
41  setUri(FaceUri(m_localEndpoint));
42 }
43 
44 void
46  const ConnectFailedCallback& onAcceptFailed,
47  int backlog/* = tcp::acceptor::max_connections*/)
48 {
49  if (isListening()) {
50  NFD_LOG_WARN("[" << m_localEndpoint << "] Already listening");
51  return;
52  }
53 
54  m_acceptor.open(m_localEndpoint.protocol());
55  m_acceptor.set_option(ip::tcp::acceptor::reuse_address(true));
56  if (m_localEndpoint.address().is_v6())
57  m_acceptor.set_option(ip::v6_only(true));
58 
59  m_acceptor.bind(m_localEndpoint);
60  m_acceptor.listen(backlog);
61 
62  // start accepting connections
63  accept(onFaceCreated, onAcceptFailed);
64 }
65 
66 void
67 TcpChannel::connect(const tcp::Endpoint& remoteEndpoint,
68  const TcpChannel::FaceCreatedCallback& onFaceCreated,
69  const TcpChannel::ConnectFailedCallback& onConnectFailed,
70  const time::seconds& timeout/* = time::seconds(4)*/)
71 {
72  auto it = m_channelFaces.find(remoteEndpoint);
73  if (it != m_channelFaces.end()) {
74  onFaceCreated(it->second);
75  return;
76  }
77 
78  auto clientSocket = make_shared<ip::tcp::socket>(ref(getGlobalIoService()));
79 
80  scheduler::EventId connectTimeoutEvent = scheduler::schedule(timeout,
81  bind(&TcpChannel::handleConnectTimeout, this, clientSocket, onConnectFailed));
82 
83  clientSocket->async_connect(remoteEndpoint,
84  bind(&TcpChannel::handleConnect, this,
85  boost::asio::placeholders::error,
86  clientSocket, connectTimeoutEvent,
87  onFaceCreated, onConnectFailed));
88 }
89 
90 size_t
92 {
93  return m_channelFaces.size();
94 }
95 
96 void
97 TcpChannel::createFace(ip::tcp::socket socket,
98  const FaceCreatedCallback& onFaceCreated,
99  bool isOnDemand)
100 {
101  shared_ptr<Face> face;
102  tcp::Endpoint remoteEndpoint = socket.remote_endpoint();
103 
104  auto it = m_channelFaces.find(remoteEndpoint);
105  if (it == m_channelFaces.end()) {
106  tcp::Endpoint localEndpoint = socket.local_endpoint();
107 
108  if (localEndpoint.address().is_loopback() &&
109  remoteEndpoint.address().is_loopback())
110  face = make_shared<TcpLocalFace>(FaceUri(remoteEndpoint), FaceUri(localEndpoint),
111  std::move(socket), isOnDemand);
112  else
113  face = make_shared<TcpFace>(FaceUri(remoteEndpoint), FaceUri(localEndpoint),
114  std::move(socket), isOnDemand);
115 
116  face->onFail.connectSingleShot([this, remoteEndpoint] (const std::string&) {
117  NFD_LOG_TRACE("Erasing " << remoteEndpoint << " from channel face map");
118  m_channelFaces.erase(remoteEndpoint);
119  });
120  m_channelFaces[remoteEndpoint] = face;
121  }
122  else {
123  // we already have a face for this endpoint, just reuse it
124  face = it->second;
125 
126  boost::system::error_code error;
127  socket.shutdown(ip::tcp::socket::shutdown_both, error);
128  socket.close(error);
129  }
130 
131  // Need to invoke the callback regardless of whether or not we have already created
132  // the face so that control responses and such can be sent.
133  onFaceCreated(face);
134 }
135 
136 void
137 TcpChannel::accept(const FaceCreatedCallback& onFaceCreated,
138  const ConnectFailedCallback& onAcceptFailed)
139 {
140  m_acceptor.async_accept(m_acceptSocket, bind(&TcpChannel::handleAccept, this,
141  boost::asio::placeholders::error,
142  onFaceCreated, onAcceptFailed));
143 }
144 
145 void
146 TcpChannel::handleAccept(const boost::system::error_code& error,
147  const FaceCreatedCallback& onFaceCreated,
148  const ConnectFailedCallback& onAcceptFailed)
149 {
150  if (error) {
151  if (error == boost::asio::error::operation_aborted) // when the socket is closed by someone
152  return;
153 
154  NFD_LOG_DEBUG("[" << m_localEndpoint << "] Accept failed: " << error.message());
155  if (onAcceptFailed)
156  onAcceptFailed(error.message());
157  return;
158  }
159 
160  NFD_LOG_DEBUG("[" << m_localEndpoint << "] Connection from " << m_acceptSocket.remote_endpoint());
161 
162  createFace(std::move(m_acceptSocket), onFaceCreated, true);
163 
164  // prepare accepting the next connection
165  accept(onFaceCreated, onAcceptFailed);
166 }
167 
168 void
169 TcpChannel::handleConnect(const boost::system::error_code& error,
170  const shared_ptr<ip::tcp::socket>& socket,
171  const scheduler::EventId& connectTimeoutEvent,
172  const FaceCreatedCallback& onFaceCreated,
173  const ConnectFailedCallback& onConnectFailed)
174 {
175  scheduler::cancel(connectTimeoutEvent);
176 
177 #if (BOOST_VERSION == 105400)
178  // To handle regression in Boost 1.54
179  // https://svn.boost.org/trac/boost/ticket/8795
180  boost::system::error_code anotherErrorCode;
181  socket->remote_endpoint(anotherErrorCode);
182  if (error || anotherErrorCode) {
183 #else
184  if (error) {
185 #endif
186  if (error == boost::asio::error::operation_aborted) // when the socket is closed by someone
187  return;
188 
189  NFD_LOG_WARN("[" << m_localEndpoint << "] Connect failed: " << error.message());
190 
191  socket->close();
192 
193  if (onConnectFailed)
194  onConnectFailed(error.message());
195  return;
196  }
197 
198  NFD_LOG_DEBUG("[" << m_localEndpoint << "] Connected to " << socket->remote_endpoint());
199 
200  createFace(std::move(*socket), onFaceCreated, false);
201 }
202 
203 void
204 TcpChannel::handleConnectTimeout(const shared_ptr<ip::tcp::socket>& socket,
205  const ConnectFailedCallback& onConnectFailed)
206 {
207  NFD_LOG_DEBUG("Connect to remote endpoint timed out");
208 
209  // abort the connection attempt
210  boost::system::error_code error;
211  socket->close(error);
212 
213  if (onConnectFailed)
214  onConnectFailed("Connect to remote endpoint timed out");
215 }
216 
217 } // namespace nfd
#define NFD_LOG_DEBUG(expression)
Definition: logger.hpp:36
void cancel(const EventId &eventId)
cancel a scheduled event
Definition: scheduler.cpp:58
represents the underlying protocol and address used by a Face
Definition: face-uri.hpp:44
std::shared_ptr< ns3::EventId > EventId
Definition: scheduler.hpp:39
TcpChannel(const tcp::Endpoint &localEndpoint)
Create TCP channel for the local endpoint.
Definition: tcp-channel.cpp:36
#define NFD_LOG_WARN(expression)
Definition: logger.hpp:39
Copyright (c) 2011-2015 Regents of the University of California.
Definition: ndn-common.hpp:38
boost::asio::ip::tcp::endpoint Endpoint
Definition: tcp-channel.hpp:35
bool isListening() const
EventId schedule(const time::nanoseconds &after, const std::function< void()> &event)
schedule an event
Definition: scheduler.cpp:50
void setUri(const FaceUri &uri)
Definition: channel.cpp:34
function< void(const std::string &reason)> ConnectFailedCallback
Prototype for the callback that is called when face is failed to get created.
Definition: channel.hpp:46
void listen(const FaceCreatedCallback &onFaceCreated, const ConnectFailedCallback &onAcceptFailed, int backlog=boost::asio::ip::tcp::acceptor::max_connections)
Enable listening on the local endpoint, accept connections, and create faces when remote host makes a...
Definition: tcp-channel.cpp:45
void connect(const tcp::Endpoint &remoteEndpoint, const FaceCreatedCallback &onFaceCreated, const ConnectFailedCallback &onConnectFailed, const time::seconds &timeout=time::seconds(4))
Create a face by establishing connection to remote endpoint.
Definition: tcp-channel.cpp:67
#define NFD_LOG_INIT(name)
Definition: logger.hpp:33
#define NFD_LOG_TRACE(expression)
Definition: logger.hpp:35
boost::asio::io_service & getGlobalIoService()
Definition: global-io.hpp:35
size_t size() const
Get number of faces in the channel.
Definition: tcp-channel.cpp:91
function< void(const shared_ptr< Face > &newFace)> FaceCreatedCallback
Prototype for the callback called when face is created (as a response to incoming connection or after...
Definition: channel.hpp:41