blob: bbefa44da9182a46eb945260c852014ba1f94e32 [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 Afanasyev8ad71ba2014-01-27 00:07:14 -080045 shared_ptr<ip::tcp::socket> clientSocket =
46 make_shared<ip::tcp::socket>(boost::ref(m_ioService));
47
48 shared_ptr<monotonic_deadline_timer> connectTimeoutTimer =
49 make_shared<monotonic_deadline_timer>(boost::ref(m_ioService));
50
51 // not sure if it works. This will bind to something...
52 // Do we need reuse here too?
53 clientSocket->bind(m_localEndpoint);
54
55 clientSocket->async_connect(remoteEndpoint,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -080056 bind(&TcpChannel::handleSuccessfulConnect, this, _1,
57 clientSocket, connectTimeoutTimer,
58 onFaceCreated, onConnectFailed));
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080059
60 connectTimeoutTimer->expires_from_now(timeout);
Alexander Afanasyev855a53c2014-01-27 12:03:00 -080061 connectTimeoutTimer->async_wait(bind(&TcpChannel::handleFailedConnect, this, _1,
62 clientSocket, connectTimeoutTimer,
63 onConnectFailed));
Alexander Afanasyeva9034b02014-01-26 18:32:02 -080064}
65
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080066void
67TcpChannel::connect(const std::string& remoteHost, const std::string& remotePort,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -080068 const TcpChannel::FaceCreatedCallback& onFaceCreated,
69 const TcpChannel::ConnectFailedCallback& onConnectFailed,
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080070 const time::Duration& timeout/* = time::seconds(4)*/)
71{
72 shared_ptr<ip::tcp::socket> clientSocket =
73 make_shared<ip::tcp::socket>(boost::ref(m_ioService));
74
75 shared_ptr<monotonic_deadline_timer> connectTimeoutTimer =
76 make_shared<monotonic_deadline_timer>(boost::ref(m_ioService));
77
78 // not sure if it works. This will bind to something...
79 // Do we need reuse here too?
80 clientSocket->bind(m_localEndpoint);
81
82 ip::tcp::resolver::query query(remoteHost, remotePort);
83 shared_ptr<ip::tcp::resolver> resolver =
84 make_shared<ip::tcp::resolver>(boost::ref(m_ioService));
85
86 resolver->async_resolve(query,
87 bind(&TcpChannel::handleEndpointResoution, this, _1, _2,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -080088 clientSocket, connectTimeoutTimer,
89 onFaceCreated, onConnectFailed));
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080090
91 connectTimeoutTimer->expires_from_now(timeout);
Alexander Afanasyev855a53c2014-01-27 12:03:00 -080092 connectTimeoutTimer->async_wait(bind(&TcpChannel::handleFailedConnect, this, _1,
93 clientSocket, connectTimeoutTimer,
94 onConnectFailed));
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080095}
96
97
98void
99TcpChannel::handleConnection(const boost::system::error_code& error,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -0800100 const shared_ptr<ip::tcp::socket>& socket,
101 const FaceCreatedCallback& onFaceCreated,
102 const ConnectFailedCallback& onConnectFailed)
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800103{
104 if (error) {
105 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
106 return;
107
108 /// \todo Log the error
109 onConnectFailed("Connect to remote endpoint failed: " +
110 error.category().message(error.value()));
111 return;
112 }
113
114 /**
Alexander Afanasyev855a53c2014-01-27 12:03:00 -0800115 * \todo Remove FaceId from here
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800116 */
117 shared_ptr<TcpFace> face = make_shared<TcpFace>(1, boost::cref(socket));
Alexander Afanasyev855a53c2014-01-27 12:03:00 -0800118 onFaceCreated(face);
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800119}
120
121void
122TcpChannel::handleSuccessfulConnect(const boost::system::error_code& error,
123 const shared_ptr<ip::tcp::socket>& socket,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -0800124 const shared_ptr<monotonic_deadline_timer>& timer,
125 const FaceCreatedCallback& onFaceCreated,
126 const ConnectFailedCallback& onConnectFailed)
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800127{
128 timer->cancel();
129
130 if (error) {
131 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
132 return;
133
134 socket->close();
135 onConnectFailed("Connect to remote endpoint failed: " +
136 error.category().message(error.value()));
137 return;
138 }
139
Alexander Afanasyev855a53c2014-01-27 12:03:00 -0800140 handleConnection(error, socket, onFaceCreated, onConnectFailed);
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800141}
142
143void
144TcpChannel::handleFailedConnect(const boost::system::error_code& error,
145 const shared_ptr<ip::tcp::socket>& socket,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -0800146 const shared_ptr<monotonic_deadline_timer>& timer,
147 const ConnectFailedCallback& onConnectFailed)
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800148{
149 if (error) { // e.g., cancelled
150 return;
151 }
152
153 onConnectFailed("Connect to remote endpoint timed out: " +
154 error.category().message(error.value()));
155 socket->close(); // abort the connection
156}
157
158void
159TcpChannel::handleEndpointResoution(const boost::system::error_code& error,
160 ip::tcp::resolver::iterator remoteEndpoint,
161 const shared_ptr<boost::asio::ip::tcp::socket>& socket,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -0800162 const shared_ptr<boost::asio::monotonic_deadline_timer>& timer,
163 const FaceCreatedCallback& onFaceCreated,
164 const ConnectFailedCallback& onConnectFailed)
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800165{
166 if (error ||
167 remoteEndpoint == ip::tcp::resolver::iterator())
168 {
169 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
170 return;
171
172 socket->close();
173 timer->cancel();
174 onConnectFailed("Remote endpoint hostname or port cannot be resolved: " +
175 error.category().message(error.value()));
176 return;
177 }
178
179 // got endpoint, now trying to connect (only try the first resolution option)
180 socket->async_connect(*remoteEndpoint,
Alexander Afanasyev855a53c2014-01-27 12:03:00 -0800181 bind(&TcpChannel::handleSuccessfulConnect, this, _1,
182 socket, timer,
183 onFaceCreated, onConnectFailed));
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -0800184}
185
186
Alexander Afanasyeva9034b02014-01-26 18:32:02 -0800187} // namespace ndn