blob: 9da453eb03933fcec85735e1f2ceb692296e090d [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
9namespace ndn {
10
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080011using namespace boost::asio;
12
13TcpChannel::TcpChannel(io_service& ioService,
14 const tcp::Endpoint& localEndpoint)
15 : m_ioService(ioService)
16 , m_localEndpoint(localEndpoint)
Alexander Afanasyeva9034b02014-01-26 18:32:02 -080017{
18}
19
20void
Alexander Afanasyev855a53c2014-01-27 12:03:00 -080021TcpChannel::listen(const FaceCreatedCallback& onFaceCreated,
22 const ConnectFailedCallback& onAcceptFailed,
23 int backlog/* = tcp::acceptor::max_connections*/)
Alexander Afanasyeva9034b02014-01-26 18:32:02 -080024{
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080025 m_acceptor = make_shared<ip::tcp::acceptor>(boost::ref(m_ioService));
26 m_acceptor->open(m_localEndpoint.protocol());
27 m_acceptor->set_option(ip::tcp::acceptor::reuse_address(true));
28 m_acceptor->bind(m_localEndpoint);
29 m_acceptor->listen(backlog);
30
31 shared_ptr<ip::tcp::socket> clientSocket =
32 make_shared<ip::tcp::socket>(boost::ref(m_ioService));
33 m_acceptor->async_accept(*clientSocket,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -080034 bind(&TcpChannel::handleConnection, this, _1,
35 clientSocket,
36 onFaceCreated, onAcceptFailed));
Alexander Afanasyeva9034b02014-01-26 18:32:02 -080037}
38
39void
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080040TcpChannel::connect(const tcp::Endpoint& remoteEndpoint,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -080041 const TcpChannel::FaceCreatedCallback& onFaceCreated,
42 const TcpChannel::ConnectFailedCallback& onConnectFailed,
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080043 const time::Duration& timeout/* = time::seconds(4)*/)
Alexander Afanasyeva9034b02014-01-26 18:32:02 -080044{
Alexander Afanasyev334b7142014-01-28 12:59:39 -080045 ChannelFaceMap::iterator i = m_channelFaces.find(remoteEndpoint);
46 if (i != m_channelFaces.end()) {
47 onFaceCreated(i->second);
48 return;
49 }
50
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080051 shared_ptr<ip::tcp::socket> clientSocket =
52 make_shared<ip::tcp::socket>(boost::ref(m_ioService));
53
54 shared_ptr<monotonic_deadline_timer> connectTimeoutTimer =
55 make_shared<monotonic_deadline_timer>(boost::ref(m_ioService));
56
57 // not sure if it works. This will bind to something...
58 // Do we need reuse here too?
59 clientSocket->bind(m_localEndpoint);
60
61 clientSocket->async_connect(remoteEndpoint,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -080062 bind(&TcpChannel::handleSuccessfulConnect, this, _1,
63 clientSocket, connectTimeoutTimer,
64 onFaceCreated, onConnectFailed));
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080065
66 connectTimeoutTimer->expires_from_now(timeout);
Alexander Afanasyev855a53c2014-01-27 12:03:00 -080067 connectTimeoutTimer->async_wait(bind(&TcpChannel::handleFailedConnect, this, _1,
68 clientSocket, connectTimeoutTimer,
69 onConnectFailed));
Alexander Afanasyeva9034b02014-01-26 18:32:02 -080070}
71
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080072void
73TcpChannel::connect(const std::string& remoteHost, const std::string& remotePort,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -080074 const TcpChannel::FaceCreatedCallback& onFaceCreated,
75 const TcpChannel::ConnectFailedCallback& onConnectFailed,
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080076 const time::Duration& timeout/* = time::seconds(4)*/)
77{
78 shared_ptr<ip::tcp::socket> clientSocket =
79 make_shared<ip::tcp::socket>(boost::ref(m_ioService));
80
81 shared_ptr<monotonic_deadline_timer> connectTimeoutTimer =
82 make_shared<monotonic_deadline_timer>(boost::ref(m_ioService));
83
84 // not sure if it works. This will bind to something...
85 // Do we need reuse here too?
86 clientSocket->bind(m_localEndpoint);
87
88 ip::tcp::resolver::query query(remoteHost, remotePort);
89 shared_ptr<ip::tcp::resolver> resolver =
90 make_shared<ip::tcp::resolver>(boost::ref(m_ioService));
91
92 resolver->async_resolve(query,
93 bind(&TcpChannel::handleEndpointResoution, this, _1, _2,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -080094 clientSocket, connectTimeoutTimer,
95 onFaceCreated, onConnectFailed));
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
103
104void
105TcpChannel::handleConnection(const boost::system::error_code& error,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -0800106 const shared_ptr<ip::tcp::socket>& socket,
107 const FaceCreatedCallback& onFaceCreated,
108 const ConnectFailedCallback& onConnectFailed)
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800109{
110 if (error) {
111 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
112 return;
113
114 /// \todo Log the error
115 onConnectFailed("Connect to remote endpoint failed: " +
116 error.category().message(error.value()));
117 return;
118 }
119
120 /**
Alexander Afanasyev855a53c2014-01-27 12:03:00 -0800121 * \todo Remove FaceId from here
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800122 */
123 shared_ptr<TcpFace> face = make_shared<TcpFace>(1, boost::cref(socket));
Alexander Afanasyev855a53c2014-01-27 12:03:00 -0800124 onFaceCreated(face);
Alexander Afanasyev334b7142014-01-28 12:59:39 -0800125
126 tcp::Endpoint remoteEndpoint = socket->remote_endpoint();
127 m_channelFaces[remoteEndpoint] = face;
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800128}
129
130void
131TcpChannel::handleSuccessfulConnect(const boost::system::error_code& error,
132 const shared_ptr<ip::tcp::socket>& socket,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -0800133 const shared_ptr<monotonic_deadline_timer>& timer,
134 const FaceCreatedCallback& onFaceCreated,
135 const ConnectFailedCallback& onConnectFailed)
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800136{
137 timer->cancel();
138
139 if (error) {
140 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
141 return;
142
143 socket->close();
144 onConnectFailed("Connect to remote endpoint failed: " +
145 error.category().message(error.value()));
146 return;
147 }
148
Alexander Afanasyev855a53c2014-01-27 12:03:00 -0800149 handleConnection(error, socket, onFaceCreated, onConnectFailed);
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800150}
151
152void
153TcpChannel::handleFailedConnect(const boost::system::error_code& error,
154 const shared_ptr<ip::tcp::socket>& socket,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -0800155 const shared_ptr<monotonic_deadline_timer>& timer,
156 const ConnectFailedCallback& onConnectFailed)
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800157{
158 if (error) { // e.g., cancelled
159 return;
160 }
161
162 onConnectFailed("Connect to remote endpoint timed out: " +
163 error.category().message(error.value()));
164 socket->close(); // abort the connection
165}
166
167void
168TcpChannel::handleEndpointResoution(const boost::system::error_code& error,
169 ip::tcp::resolver::iterator remoteEndpoint,
170 const shared_ptr<boost::asio::ip::tcp::socket>& socket,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -0800171 const shared_ptr<boost::asio::monotonic_deadline_timer>& timer,
172 const FaceCreatedCallback& onFaceCreated,
173 const ConnectFailedCallback& onConnectFailed)
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800174{
175 if (error ||
176 remoteEndpoint == ip::tcp::resolver::iterator())
177 {
178 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
179 return;
180
181 socket->close();
182 timer->cancel();
183 onConnectFailed("Remote endpoint hostname or port cannot be resolved: " +
184 error.category().message(error.value()));
185 return;
186 }
187
188 // got endpoint, now trying to connect (only try the first resolution option)
189 socket->async_connect(*remoteEndpoint,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -0800190 bind(&TcpChannel::handleSuccessfulConnect, this, _1,
191 socket, timer,
192 onFaceCreated, onConnectFailed));
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800193}
194
195
Alexander Afanasyeva9034b02014-01-26 18:32:02 -0800196} // namespace ndn