blob: e3ad8d554a9f00b9ab443c5d4437682a6c7013b7 [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"
8
Alexander Afanasyev18bbf812014-01-29 01:40:23 -08009namespace nfd {
Alexander Afanasyeva9034b02014-01-26 18:32:02 -080010
Alexander Afanasyev3958b012014-01-31 15:06:13 -080011NFD_LOG_INIT("TcpChannel");
12
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080013using namespace boost::asio;
14
15TcpChannel::TcpChannel(io_service& ioService,
16 const tcp::Endpoint& localEndpoint)
17 : m_ioService(ioService)
18 , m_localEndpoint(localEndpoint)
Alexander Afanasyeva9034b02014-01-26 18:32:02 -080019{
20}
21
22void
Alexander Afanasyev855a53c2014-01-27 12:03:00 -080023TcpChannel::listen(const FaceCreatedCallback& onFaceCreated,
24 const ConnectFailedCallback& onAcceptFailed,
25 int backlog/* = tcp::acceptor::max_connections*/)
Alexander Afanasyeva9034b02014-01-26 18:32:02 -080026{
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080027 m_acceptor = make_shared<ip::tcp::acceptor>(boost::ref(m_ioService));
28 m_acceptor->open(m_localEndpoint.protocol());
29 m_acceptor->set_option(ip::tcp::acceptor::reuse_address(true));
30 m_acceptor->bind(m_localEndpoint);
31 m_acceptor->listen(backlog);
32
33 shared_ptr<ip::tcp::socket> clientSocket =
34 make_shared<ip::tcp::socket>(boost::ref(m_ioService));
35 m_acceptor->async_accept(*clientSocket,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -080036 bind(&TcpChannel::handleConnection, this, _1,
37 clientSocket,
Alexander Afanasyev3958b012014-01-31 15:06:13 -080038 onFaceCreated, onAcceptFailed,
39 true));
Alexander Afanasyeva9034b02014-01-26 18:32:02 -080040}
41
42void
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080043TcpChannel::connect(const tcp::Endpoint& remoteEndpoint,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -080044 const TcpChannel::FaceCreatedCallback& onFaceCreated,
45 const TcpChannel::ConnectFailedCallback& onConnectFailed,
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080046 const time::Duration& timeout/* = time::seconds(4)*/)
Alexander Afanasyeva9034b02014-01-26 18:32:02 -080047{
Alexander Afanasyev334b7142014-01-28 12:59:39 -080048 ChannelFaceMap::iterator i = m_channelFaces.find(remoteEndpoint);
49 if (i != m_channelFaces.end()) {
50 onFaceCreated(i->second);
51 return;
52 }
53
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080054 shared_ptr<ip::tcp::socket> clientSocket =
55 make_shared<ip::tcp::socket>(boost::ref(m_ioService));
56
57 shared_ptr<monotonic_deadline_timer> connectTimeoutTimer =
58 make_shared<monotonic_deadline_timer>(boost::ref(m_ioService));
59
Alexander Afanasyev3958b012014-01-31 15:06:13 -080060 clientSocket->open(m_localEndpoint.protocol());
61
62 // The following does not work and CCNx does not bind the local
63 // socket to a fixed port number for TCP connections
64
65 // clientSocket->set_option(ip::tcp::socket::reuse_address(true));
66 // clientSocket->bind(m_localEndpoint);
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080067
68 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 Afanasyev8ad71ba2014-01-27 00:07:14 -080083 const time::Duration& timeout/* = time::seconds(4)*/)
84{
85 shared_ptr<ip::tcp::socket> clientSocket =
86 make_shared<ip::tcp::socket>(boost::ref(m_ioService));
87
88 shared_ptr<monotonic_deadline_timer> connectTimeoutTimer =
89 make_shared<monotonic_deadline_timer>(boost::ref(m_ioService));
90
Alexander Afanasyev3958b012014-01-31 15:06:13 -080091 clientSocket->open(m_localEndpoint.protocol());
92
93 // The following does not work and CCNx does not bind the local
94 // socket to a fixed port number for TCP connections
95
96 // clientSocket->set_option(ip::tcp::socket::reuse_address(true));
97 // clientSocket->bind(m_localEndpoint);
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080098
99 ip::tcp::resolver::query query(remoteHost, remotePort);
100 shared_ptr<ip::tcp::resolver> resolver =
101 make_shared<ip::tcp::resolver>(boost::ref(m_ioService));
102
103 resolver->async_resolve(query,
104 bind(&TcpChannel::handleEndpointResoution, this, _1, _2,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -0800105 clientSocket, connectTimeoutTimer,
Alexander Afanasyev3958b012014-01-31 15:06:13 -0800106 onFaceCreated, onConnectFailed,
107 resolver));
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800108
109 connectTimeoutTimer->expires_from_now(timeout);
Alexander Afanasyev855a53c2014-01-27 12:03:00 -0800110 connectTimeoutTimer->async_wait(bind(&TcpChannel::handleFailedConnect, this, _1,
111 clientSocket, connectTimeoutTimer,
112 onConnectFailed));
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800113}
114
115
116void
117TcpChannel::handleConnection(const boost::system::error_code& error,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -0800118 const shared_ptr<ip::tcp::socket>& socket,
119 const FaceCreatedCallback& onFaceCreated,
Alexander Afanasyev3958b012014-01-31 15:06:13 -0800120 const ConnectFailedCallback& onConnectFailed,
121 bool remoteConnection)
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800122{
123 if (error) {
124 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
125 return;
126
Alexander Afanasyev3958b012014-01-31 15:06:13 -0800127 NFD_LOG_DEBUG("Connect to remote endpoint failed: "
128 << error.category().message(error.value()));
129
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800130 onConnectFailed("Connect to remote endpoint failed: " +
131 error.category().message(error.value()));
132 return;
133 }
134
Alexander Afanasyev3958b012014-01-31 15:06:13 -0800135 if (remoteConnection)
136 {
137 NFD_LOG_DEBUG("[" << socket->local_endpoint() << "] "
138 "<< Connection from " << socket->remote_endpoint());
139 }
140 else
141 {
142 NFD_LOG_DEBUG("[" << socket->local_endpoint() << "] "
143 ">> Connection to " << socket->remote_endpoint());
144 }
145
146 /**
147 * \todo Remove FaceId from here
148 */
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700149 shared_ptr<TcpFace> face = make_shared<TcpFace>(boost::cref(socket));
Alexander Afanasyev855a53c2014-01-27 12:03:00 -0800150 onFaceCreated(face);
Alexander Afanasyev334b7142014-01-28 12:59:39 -0800151
152 tcp::Endpoint remoteEndpoint = socket->remote_endpoint();
153 m_channelFaces[remoteEndpoint] = face;
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800154}
155
156void
157TcpChannel::handleSuccessfulConnect(const boost::system::error_code& error,
158 const shared_ptr<ip::tcp::socket>& socket,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -0800159 const shared_ptr<monotonic_deadline_timer>& timer,
160 const FaceCreatedCallback& onFaceCreated,
161 const ConnectFailedCallback& onConnectFailed)
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800162{
163 timer->cancel();
164
165 if (error) {
166 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
167 return;
168
169 socket->close();
Alexander Afanasyev3958b012014-01-31 15:06:13 -0800170
171 NFD_LOG_DEBUG("Connect to remote endpoint failed: "
172 << error.category().message(error.value()));
173
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800174 onConnectFailed("Connect to remote endpoint failed: " +
175 error.category().message(error.value()));
176 return;
177 }
178
Alexander Afanasyev3958b012014-01-31 15:06:13 -0800179 handleConnection(error, socket, onFaceCreated, onConnectFailed, false);
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800180}
181
182void
183TcpChannel::handleFailedConnect(const boost::system::error_code& error,
184 const shared_ptr<ip::tcp::socket>& socket,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -0800185 const shared_ptr<monotonic_deadline_timer>& timer,
186 const ConnectFailedCallback& onConnectFailed)
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800187{
188 if (error) { // e.g., cancelled
189 return;
190 }
191
Alexander Afanasyev3958b012014-01-31 15:06:13 -0800192 NFD_LOG_DEBUG("Connect to remote endpoint timed out: "
193 << error.category().message(error.value()));
194
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800195 onConnectFailed("Connect to remote endpoint timed out: " +
196 error.category().message(error.value()));
197 socket->close(); // abort the connection
198}
199
200void
201TcpChannel::handleEndpointResoution(const boost::system::error_code& error,
202 ip::tcp::resolver::iterator remoteEndpoint,
203 const shared_ptr<boost::asio::ip::tcp::socket>& socket,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -0800204 const shared_ptr<boost::asio::monotonic_deadline_timer>& timer,
205 const FaceCreatedCallback& onFaceCreated,
Alexander Afanasyev3958b012014-01-31 15:06:13 -0800206 const ConnectFailedCallback& onConnectFailed,
207 const shared_ptr<ip::tcp::resolver>& resolver)
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800208{
209 if (error ||
210 remoteEndpoint == ip::tcp::resolver::iterator())
211 {
212 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
213 return;
214
215 socket->close();
216 timer->cancel();
Alexander Afanasyev3958b012014-01-31 15:06:13 -0800217
218 NFD_LOG_DEBUG("Remote endpoint hostname or port cannot be resolved: "
219 << error.category().message(error.value()));
220
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800221 onConnectFailed("Remote endpoint hostname or port cannot be resolved: " +
222 error.category().message(error.value()));
223 return;
224 }
225
226 // got endpoint, now trying to connect (only try the first resolution option)
227 socket->async_connect(*remoteEndpoint,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -0800228 bind(&TcpChannel::handleSuccessfulConnect, this, _1,
229 socket, timer,
230 onFaceCreated, onConnectFailed));
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800231}
232
233
Alexander Afanasyev18bbf812014-01-29 01:40:23 -0800234} // namespace nfd