blob: 28fdfa54447e89c3dc7b386345c8b50316430b80 [file] [log] [blame]
Alexander Afanasyeva9034b02014-01-26 18:32:02 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (C) 2014 Named Data Networking Project
4 * See COPYING for copyright and distribution information.
5 */
6
7#include "tcp-channel.hpp"
Junxiao Shi61e3cc52014-03-03 20:40:28 -07008#include "core/global-io.hpp"
9#include "core/face-uri.hpp"
Alexander Afanasyeva9034b02014-01-26 18:32:02 -080010
Alexander Afanasyev18bbf812014-01-29 01:40:23 -080011namespace nfd {
Alexander Afanasyeva9034b02014-01-26 18:32:02 -080012
Alexander Afanasyev3958b012014-01-31 15:06:13 -080013NFD_LOG_INIT("TcpChannel");
14
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080015using namespace boost::asio;
16
Junxiao Shi61e3cc52014-03-03 20:40:28 -070017TcpChannel::TcpChannel(const tcp::Endpoint& localEndpoint)
18 : m_localEndpoint(localEndpoint)
19{
20 this->setUri(FaceUri(localEndpoint));
21}
22
23TcpChannel::~TcpChannel()
Alexander Afanasyeva9034b02014-01-26 18:32:02 -080024{
25}
26
27void
Alexander Afanasyev855a53c2014-01-27 12:03:00 -080028TcpChannel::listen(const FaceCreatedCallback& onFaceCreated,
29 const ConnectFailedCallback& onAcceptFailed,
30 int backlog/* = tcp::acceptor::max_connections*/)
Alexander Afanasyeva9034b02014-01-26 18:32:02 -080031{
Junxiao Shi61e3cc52014-03-03 20:40:28 -070032 m_acceptor = make_shared<ip::tcp::acceptor>(boost::ref(getGlobalIoService()));
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080033 m_acceptor->open(m_localEndpoint.protocol());
34 m_acceptor->set_option(ip::tcp::acceptor::reuse_address(true));
Alexander Afanasyeveee71fd2014-03-13 17:40:33 -070035 if (m_localEndpoint.address().is_v6())
36 {
37 m_acceptor->set_option(ip::v6_only(true));
38 }
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080039 m_acceptor->bind(m_localEndpoint);
40 m_acceptor->listen(backlog);
41
42 shared_ptr<ip::tcp::socket> clientSocket =
Junxiao Shi61e3cc52014-03-03 20:40:28 -070043 make_shared<ip::tcp::socket>(boost::ref(getGlobalIoService()));
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080044 m_acceptor->async_accept(*clientSocket,
Alexander Afanasyeva16abd22014-01-31 18:12:29 -080045 bind(&TcpChannel::handleSuccessfulAccept, this, _1,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -080046 clientSocket,
Alexander Afanasyeva16abd22014-01-31 18:12:29 -080047 onFaceCreated, onAcceptFailed));
Alexander Afanasyeva9034b02014-01-26 18:32:02 -080048}
49
50void
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080051TcpChannel::connect(const tcp::Endpoint& remoteEndpoint,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -080052 const TcpChannel::FaceCreatedCallback& onFaceCreated,
53 const TcpChannel::ConnectFailedCallback& onConnectFailed,
Alexander Afanasyeveb3197f2014-03-17 19:28:18 -070054 const time::seconds& timeout/* = time::seconds(4)*/)
Alexander Afanasyeva9034b02014-01-26 18:32:02 -080055{
Alexander Afanasyev334b7142014-01-28 12:59:39 -080056 ChannelFaceMap::iterator i = m_channelFaces.find(remoteEndpoint);
57 if (i != m_channelFaces.end()) {
58 onFaceCreated(i->second);
59 return;
60 }
61
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080062 shared_ptr<ip::tcp::socket> clientSocket =
Junxiao Shi61e3cc52014-03-03 20:40:28 -070063 make_shared<ip::tcp::socket>(boost::ref(getGlobalIoService()));
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080064
Alexander Afanasyeveb3197f2014-03-17 19:28:18 -070065 shared_ptr<ndn::monotonic_deadline_timer> connectTimeoutTimer =
66 make_shared<ndn::monotonic_deadline_timer>(boost::ref(getGlobalIoService()));
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080067
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080068 clientSocket->async_connect(remoteEndpoint,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -080069 bind(&TcpChannel::handleSuccessfulConnect, this, _1,
70 clientSocket, connectTimeoutTimer,
71 onFaceCreated, onConnectFailed));
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080072
73 connectTimeoutTimer->expires_from_now(timeout);
Alexander Afanasyev855a53c2014-01-27 12:03:00 -080074 connectTimeoutTimer->async_wait(bind(&TcpChannel::handleFailedConnect, this, _1,
75 clientSocket, connectTimeoutTimer,
76 onConnectFailed));
Alexander Afanasyeva9034b02014-01-26 18:32:02 -080077}
78
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080079void
80TcpChannel::connect(const std::string& remoteHost, const std::string& remotePort,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -080081 const TcpChannel::FaceCreatedCallback& onFaceCreated,
82 const TcpChannel::ConnectFailedCallback& onConnectFailed,
Alexander Afanasyeveb3197f2014-03-17 19:28:18 -070083 const time::seconds& timeout/* = time::seconds(4)*/)
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080084{
85 shared_ptr<ip::tcp::socket> clientSocket =
Junxiao Shi61e3cc52014-03-03 20:40:28 -070086 make_shared<ip::tcp::socket>(boost::ref(getGlobalIoService()));
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080087
Alexander Afanasyeveb3197f2014-03-17 19:28:18 -070088 shared_ptr<ndn::monotonic_deadline_timer> connectTimeoutTimer =
89 make_shared<ndn::monotonic_deadline_timer>(boost::ref(getGlobalIoService()));
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080090
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080091 ip::tcp::resolver::query query(remoteHost, remotePort);
92 shared_ptr<ip::tcp::resolver> resolver =
Junxiao Shi61e3cc52014-03-03 20:40:28 -070093 make_shared<ip::tcp::resolver>(boost::ref(getGlobalIoService()));
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080094
95 resolver->async_resolve(query,
Davide Pesavento855bf292014-02-27 03:58:01 +010096 bind(&TcpChannel::handleEndpointResolution, this, _1, _2,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -080097 clientSocket, connectTimeoutTimer,
Alexander Afanasyev3958b012014-01-31 15:06:13 -080098 onFaceCreated, onConnectFailed,
99 resolver));
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800100
101 connectTimeoutTimer->expires_from_now(timeout);
Alexander Afanasyev855a53c2014-01-27 12:03:00 -0800102 connectTimeoutTimer->async_wait(bind(&TcpChannel::handleFailedConnect, this, _1,
103 clientSocket, connectTimeoutTimer,
104 onConnectFailed));
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800105}
106
Alexander Afanasyeva0a10fb2014-02-13 19:56:15 -0800107size_t
108TcpChannel::size() const
109{
110 return m_channelFaces.size();
111}
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800112
113void
Alexander Afanasyeva16abd22014-01-31 18:12:29 -0800114TcpChannel::createFace(const shared_ptr<ip::tcp::socket>& socket,
Alexander Afanasyev355c0662014-03-20 18:08:17 -0700115 const FaceCreatedCallback& onFaceCreated,
116 bool isOnDemand)
Alexander Afanasyeva16abd22014-01-31 18:12:29 -0800117{
Alexander Afanasyeva16abd22014-01-31 18:12:29 -0800118 tcp::Endpoint remoteEndpoint = socket->remote_endpoint();
Alexander Afanasyeva0a10fb2014-02-13 19:56:15 -0800119
Alexander Afanasyevbd220a02014-02-20 00:29:56 -0800120 shared_ptr<Face> face;
Alexander Afanasyevbfd31de2014-02-26 13:20:08 -0800121 if (socket->local_endpoint().address().is_loopback())
Alexander Afanasyev355c0662014-03-20 18:08:17 -0700122 face = make_shared<TcpLocalFace>(boost::cref(socket), isOnDemand);
Alexander Afanasyevbd220a02014-02-20 00:29:56 -0800123 else
Alexander Afanasyev355c0662014-03-20 18:08:17 -0700124 face = make_shared<TcpFace>(boost::cref(socket), isOnDemand);
Junxiao Shi61e3cc52014-03-03 20:40:28 -0700125
Alexander Afanasyeva0a10fb2014-02-13 19:56:15 -0800126 face->onFail += bind(&TcpChannel::afterFaceFailed, this, remoteEndpoint);
127
128 onFaceCreated(face);
Alexander Afanasyeva16abd22014-01-31 18:12:29 -0800129 m_channelFaces[remoteEndpoint] = face;
130}
131
132void
Alexander Afanasyeva0a10fb2014-02-13 19:56:15 -0800133TcpChannel::afterFaceFailed(tcp::Endpoint &remoteEndpoint)
134{
135 NFD_LOG_DEBUG("afterFaceFailed: " << remoteEndpoint);
136 m_channelFaces.erase(remoteEndpoint);
137}
138
139void
Alexander Afanasyeva16abd22014-01-31 18:12:29 -0800140TcpChannel::handleSuccessfulAccept(const boost::system::error_code& error,
141 const shared_ptr<boost::asio::ip::tcp::socket>& socket,
142 const FaceCreatedCallback& onFaceCreated,
143 const ConnectFailedCallback& onAcceptFailed)
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800144{
145 if (error) {
146 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
147 return;
148
Alexander Afanasyev3958b012014-01-31 15:06:13 -0800149 NFD_LOG_DEBUG("Connect to remote endpoint failed: "
150 << error.category().message(error.value()));
Alexander Afanasyev5f1ec252014-02-28 10:59:17 -0800151
152 if (static_cast<bool>(onAcceptFailed))
153 onAcceptFailed("Connect to remote endpoint failed: " +
154 error.category().message(error.value()));
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800155 return;
156 }
157
Alexander Afanasyeva16abd22014-01-31 18:12:29 -0800158 // prepare accepting the next connection
159 shared_ptr<ip::tcp::socket> clientSocket =
Junxiao Shi61e3cc52014-03-03 20:40:28 -0700160 make_shared<ip::tcp::socket>(boost::ref(getGlobalIoService()));
Alexander Afanasyeva16abd22014-01-31 18:12:29 -0800161 m_acceptor->async_accept(*clientSocket,
162 bind(&TcpChannel::handleSuccessfulAccept, this, _1,
163 clientSocket,
164 onFaceCreated, onAcceptFailed));
Alexander Afanasyev334b7142014-01-28 12:59:39 -0800165
Alexander Afanasyeva16abd22014-01-31 18:12:29 -0800166 NFD_LOG_DEBUG("[" << m_localEndpoint << "] "
167 "<< Connection from " << socket->remote_endpoint());
Alexander Afanasyev355c0662014-03-20 18:08:17 -0700168 createFace(socket, onFaceCreated, true);
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800169}
170
171void
172TcpChannel::handleSuccessfulConnect(const boost::system::error_code& error,
173 const shared_ptr<ip::tcp::socket>& socket,
Alexander Afanasyeveb3197f2014-03-17 19:28:18 -0700174 const shared_ptr<ndn::monotonic_deadline_timer>& timer,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -0800175 const FaceCreatedCallback& onFaceCreated,
176 const ConnectFailedCallback& onConnectFailed)
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800177{
178 timer->cancel();
179
180 if (error) {
181 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
182 return;
183
184 socket->close();
Junxiao Shi61e3cc52014-03-03 20:40:28 -0700185
Alexander Afanasyev3958b012014-01-31 15:06:13 -0800186 NFD_LOG_DEBUG("Connect to remote endpoint failed: "
187 << error.category().message(error.value()));
Junxiao Shi61e3cc52014-03-03 20:40:28 -0700188
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800189 onConnectFailed("Connect to remote endpoint failed: " +
190 error.category().message(error.value()));
191 return;
192 }
193
Alexander Afanasyeva16abd22014-01-31 18:12:29 -0800194 NFD_LOG_DEBUG("[" << m_localEndpoint << "] "
195 ">> Connection to " << socket->remote_endpoint());
Junxiao Shi61e3cc52014-03-03 20:40:28 -0700196
Alexander Afanasyev355c0662014-03-20 18:08:17 -0700197 createFace(socket, onFaceCreated, false);
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800198}
199
200void
201TcpChannel::handleFailedConnect(const boost::system::error_code& error,
202 const shared_ptr<ip::tcp::socket>& socket,
Alexander Afanasyeveb3197f2014-03-17 19:28:18 -0700203 const shared_ptr<ndn::monotonic_deadline_timer>& timer,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -0800204 const ConnectFailedCallback& onConnectFailed)
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800205{
206 if (error) { // e.g., cancelled
207 return;
208 }
209
Alexander Afanasyev3958b012014-01-31 15:06:13 -0800210 NFD_LOG_DEBUG("Connect to remote endpoint timed out: "
211 << error.category().message(error.value()));
Junxiao Shi61e3cc52014-03-03 20:40:28 -0700212
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800213 onConnectFailed("Connect to remote endpoint timed out: " +
214 error.category().message(error.value()));
215 socket->close(); // abort the connection
216}
217
218void
Davide Pesavento855bf292014-02-27 03:58:01 +0100219TcpChannel::handleEndpointResolution(const boost::system::error_code& error,
220 ip::tcp::resolver::iterator remoteEndpoint,
221 const shared_ptr<boost::asio::ip::tcp::socket>& socket,
Alexander Afanasyeveb3197f2014-03-17 19:28:18 -0700222 const shared_ptr<ndn::monotonic_deadline_timer>& timer,
Davide Pesavento855bf292014-02-27 03:58:01 +0100223 const FaceCreatedCallback& onFaceCreated,
224 const ConnectFailedCallback& onConnectFailed,
225 const shared_ptr<ip::tcp::resolver>& resolver)
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800226{
227 if (error ||
228 remoteEndpoint == ip::tcp::resolver::iterator())
229 {
230 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
231 return;
232
233 socket->close();
234 timer->cancel();
Alexander Afanasyev3958b012014-01-31 15:06:13 -0800235
236 NFD_LOG_DEBUG("Remote endpoint hostname or port cannot be resolved: "
237 << error.category().message(error.value()));
Junxiao Shi61e3cc52014-03-03 20:40:28 -0700238
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800239 onConnectFailed("Remote endpoint hostname or port cannot be resolved: " +
240 error.category().message(error.value()));
241 return;
242 }
243
244 // got endpoint, now trying to connect (only try the first resolution option)
245 socket->async_connect(*remoteEndpoint,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -0800246 bind(&TcpChannel::handleSuccessfulConnect, this, _1,
247 socket, timer,
248 onFaceCreated, onConnectFailed));
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800249}
250
Alexander Afanasyev18bbf812014-01-29 01:40:23 -0800251} // namespace nfd