blob: 35ade3b8a90d8167cdd1d6e34e0bdffa09285250 [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));
35 m_acceptor->bind(m_localEndpoint);
36 m_acceptor->listen(backlog);
37
38 shared_ptr<ip::tcp::socket> clientSocket =
Junxiao Shi61e3cc52014-03-03 20:40:28 -070039 make_shared<ip::tcp::socket>(boost::ref(getGlobalIoService()));
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080040 m_acceptor->async_accept(*clientSocket,
Alexander Afanasyeva16abd22014-01-31 18:12:29 -080041 bind(&TcpChannel::handleSuccessfulAccept, this, _1,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -080042 clientSocket,
Alexander Afanasyeva16abd22014-01-31 18:12:29 -080043 onFaceCreated, onAcceptFailed));
Alexander Afanasyeva9034b02014-01-26 18:32:02 -080044}
45
46void
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080047TcpChannel::connect(const tcp::Endpoint& remoteEndpoint,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -080048 const TcpChannel::FaceCreatedCallback& onFaceCreated,
49 const TcpChannel::ConnectFailedCallback& onConnectFailed,
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080050 const time::Duration& timeout/* = time::seconds(4)*/)
Alexander Afanasyeva9034b02014-01-26 18:32:02 -080051{
Alexander Afanasyev334b7142014-01-28 12:59:39 -080052 ChannelFaceMap::iterator i = m_channelFaces.find(remoteEndpoint);
53 if (i != m_channelFaces.end()) {
54 onFaceCreated(i->second);
55 return;
56 }
57
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080058 shared_ptr<ip::tcp::socket> clientSocket =
Junxiao Shi61e3cc52014-03-03 20:40:28 -070059 make_shared<ip::tcp::socket>(boost::ref(getGlobalIoService()));
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080060
61 shared_ptr<monotonic_deadline_timer> connectTimeoutTimer =
Junxiao Shi61e3cc52014-03-03 20:40:28 -070062 make_shared<monotonic_deadline_timer>(boost::ref(getGlobalIoService()));
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080063
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080064 clientSocket->async_connect(remoteEndpoint,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -080065 bind(&TcpChannel::handleSuccessfulConnect, this, _1,
66 clientSocket, connectTimeoutTimer,
67 onFaceCreated, onConnectFailed));
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080068
69 connectTimeoutTimer->expires_from_now(timeout);
Alexander Afanasyev855a53c2014-01-27 12:03:00 -080070 connectTimeoutTimer->async_wait(bind(&TcpChannel::handleFailedConnect, this, _1,
71 clientSocket, connectTimeoutTimer,
72 onConnectFailed));
Alexander Afanasyeva9034b02014-01-26 18:32:02 -080073}
74
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080075void
76TcpChannel::connect(const std::string& remoteHost, const std::string& remotePort,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -080077 const TcpChannel::FaceCreatedCallback& onFaceCreated,
78 const TcpChannel::ConnectFailedCallback& onConnectFailed,
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080079 const time::Duration& timeout/* = time::seconds(4)*/)
80{
81 shared_ptr<ip::tcp::socket> clientSocket =
Junxiao Shi61e3cc52014-03-03 20:40:28 -070082 make_shared<ip::tcp::socket>(boost::ref(getGlobalIoService()));
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080083
84 shared_ptr<monotonic_deadline_timer> connectTimeoutTimer =
Junxiao Shi61e3cc52014-03-03 20:40:28 -070085 make_shared<monotonic_deadline_timer>(boost::ref(getGlobalIoService()));
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080086
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080087 ip::tcp::resolver::query query(remoteHost, remotePort);
88 shared_ptr<ip::tcp::resolver> resolver =
Junxiao Shi61e3cc52014-03-03 20:40:28 -070089 make_shared<ip::tcp::resolver>(boost::ref(getGlobalIoService()));
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080090
91 resolver->async_resolve(query,
Davide Pesavento855bf292014-02-27 03:58:01 +010092 bind(&TcpChannel::handleEndpointResolution, this, _1, _2,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -080093 clientSocket, connectTimeoutTimer,
Alexander Afanasyev3958b012014-01-31 15:06:13 -080094 onFaceCreated, onConnectFailed,
95 resolver));
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080096
97 connectTimeoutTimer->expires_from_now(timeout);
Alexander Afanasyev855a53c2014-01-27 12:03:00 -080098 connectTimeoutTimer->async_wait(bind(&TcpChannel::handleFailedConnect, this, _1,
99 clientSocket, connectTimeoutTimer,
100 onConnectFailed));
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800101}
102
Alexander Afanasyeva0a10fb2014-02-13 19:56:15 -0800103size_t
104TcpChannel::size() const
105{
106 return m_channelFaces.size();
107}
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800108
109void
Alexander Afanasyeva16abd22014-01-31 18:12:29 -0800110TcpChannel::createFace(const shared_ptr<ip::tcp::socket>& socket,
111 const FaceCreatedCallback& onFaceCreated)
112{
Alexander Afanasyeva16abd22014-01-31 18:12:29 -0800113 tcp::Endpoint remoteEndpoint = socket->remote_endpoint();
Alexander Afanasyeva0a10fb2014-02-13 19:56:15 -0800114
Alexander Afanasyevbd220a02014-02-20 00:29:56 -0800115 shared_ptr<Face> face;
Alexander Afanasyevbfd31de2014-02-26 13:20:08 -0800116 if (socket->local_endpoint().address().is_loopback())
Alexander Afanasyevbd220a02014-02-20 00:29:56 -0800117 face = make_shared<TcpLocalFace>(boost::cref(socket));
118 else
119 face = make_shared<TcpFace>(boost::cref(socket));
Junxiao Shi61e3cc52014-03-03 20:40:28 -0700120
Alexander Afanasyeva0a10fb2014-02-13 19:56:15 -0800121 face->onFail += bind(&TcpChannel::afterFaceFailed, this, remoteEndpoint);
122
123 onFaceCreated(face);
Alexander Afanasyeva16abd22014-01-31 18:12:29 -0800124 m_channelFaces[remoteEndpoint] = face;
125}
126
127void
Alexander Afanasyeva0a10fb2014-02-13 19:56:15 -0800128TcpChannel::afterFaceFailed(tcp::Endpoint &remoteEndpoint)
129{
130 NFD_LOG_DEBUG("afterFaceFailed: " << remoteEndpoint);
131 m_channelFaces.erase(remoteEndpoint);
132}
133
134void
Alexander Afanasyeva16abd22014-01-31 18:12:29 -0800135TcpChannel::handleSuccessfulAccept(const boost::system::error_code& error,
136 const shared_ptr<boost::asio::ip::tcp::socket>& socket,
137 const FaceCreatedCallback& onFaceCreated,
138 const ConnectFailedCallback& onAcceptFailed)
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800139{
140 if (error) {
141 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
142 return;
143
Alexander Afanasyev3958b012014-01-31 15:06:13 -0800144 NFD_LOG_DEBUG("Connect to remote endpoint failed: "
145 << error.category().message(error.value()));
Alexander Afanasyev5f1ec252014-02-28 10:59:17 -0800146
147 if (static_cast<bool>(onAcceptFailed))
148 onAcceptFailed("Connect to remote endpoint failed: " +
149 error.category().message(error.value()));
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800150 return;
151 }
152
Alexander Afanasyeva16abd22014-01-31 18:12:29 -0800153 // prepare accepting the next connection
154 shared_ptr<ip::tcp::socket> clientSocket =
Junxiao Shi61e3cc52014-03-03 20:40:28 -0700155 make_shared<ip::tcp::socket>(boost::ref(getGlobalIoService()));
Alexander Afanasyeva16abd22014-01-31 18:12:29 -0800156 m_acceptor->async_accept(*clientSocket,
157 bind(&TcpChannel::handleSuccessfulAccept, this, _1,
158 clientSocket,
159 onFaceCreated, onAcceptFailed));
Alexander Afanasyev334b7142014-01-28 12:59:39 -0800160
Alexander Afanasyeva16abd22014-01-31 18:12:29 -0800161 NFD_LOG_DEBUG("[" << m_localEndpoint << "] "
162 "<< Connection from " << socket->remote_endpoint());
163 createFace(socket, onFaceCreated);
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800164}
165
166void
167TcpChannel::handleSuccessfulConnect(const boost::system::error_code& error,
168 const shared_ptr<ip::tcp::socket>& socket,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -0800169 const shared_ptr<monotonic_deadline_timer>& timer,
170 const FaceCreatedCallback& onFaceCreated,
171 const ConnectFailedCallback& onConnectFailed)
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800172{
173 timer->cancel();
174
175 if (error) {
176 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
177 return;
178
179 socket->close();
Junxiao Shi61e3cc52014-03-03 20:40:28 -0700180
Alexander Afanasyev3958b012014-01-31 15:06:13 -0800181 NFD_LOG_DEBUG("Connect to remote endpoint failed: "
182 << error.category().message(error.value()));
Junxiao Shi61e3cc52014-03-03 20:40:28 -0700183
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800184 onConnectFailed("Connect to remote endpoint failed: " +
185 error.category().message(error.value()));
186 return;
187 }
188
Alexander Afanasyeva16abd22014-01-31 18:12:29 -0800189 NFD_LOG_DEBUG("[" << m_localEndpoint << "] "
190 ">> Connection to " << socket->remote_endpoint());
Junxiao Shi61e3cc52014-03-03 20:40:28 -0700191
Alexander Afanasyeva16abd22014-01-31 18:12:29 -0800192 createFace(socket, onFaceCreated);
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800193}
194
195void
196TcpChannel::handleFailedConnect(const boost::system::error_code& error,
197 const shared_ptr<ip::tcp::socket>& socket,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -0800198 const shared_ptr<monotonic_deadline_timer>& timer,
199 const ConnectFailedCallback& onConnectFailed)
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800200{
201 if (error) { // e.g., cancelled
202 return;
203 }
204
Alexander Afanasyev3958b012014-01-31 15:06:13 -0800205 NFD_LOG_DEBUG("Connect to remote endpoint timed out: "
206 << error.category().message(error.value()));
Junxiao Shi61e3cc52014-03-03 20:40:28 -0700207
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800208 onConnectFailed("Connect to remote endpoint timed out: " +
209 error.category().message(error.value()));
210 socket->close(); // abort the connection
211}
212
213void
Davide Pesavento855bf292014-02-27 03:58:01 +0100214TcpChannel::handleEndpointResolution(const boost::system::error_code& error,
215 ip::tcp::resolver::iterator remoteEndpoint,
216 const shared_ptr<boost::asio::ip::tcp::socket>& socket,
217 const shared_ptr<boost::asio::monotonic_deadline_timer>& timer,
218 const FaceCreatedCallback& onFaceCreated,
219 const ConnectFailedCallback& onConnectFailed,
220 const shared_ptr<ip::tcp::resolver>& resolver)
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800221{
222 if (error ||
223 remoteEndpoint == ip::tcp::resolver::iterator())
224 {
225 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
226 return;
227
228 socket->close();
229 timer->cancel();
Alexander Afanasyev3958b012014-01-31 15:06:13 -0800230
231 NFD_LOG_DEBUG("Remote endpoint hostname or port cannot be resolved: "
232 << error.category().message(error.value()));
Junxiao Shi61e3cc52014-03-03 20:40:28 -0700233
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800234 onConnectFailed("Remote endpoint hostname or port cannot be resolved: " +
235 error.category().message(error.value()));
236 return;
237 }
238
239 // got endpoint, now trying to connect (only try the first resolution option)
240 socket->async_connect(*remoteEndpoint,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -0800241 bind(&TcpChannel::handleSuccessfulConnect, this, _1,
242 socket, timer,
243 onFaceCreated, onConnectFailed));
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800244}
245
Alexander Afanasyev18bbf812014-01-29 01:40:23 -0800246} // namespace nfd