blob: 40181619aae8dd2cee3d91e2edc05ec4a8b8f405 [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"
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -08008#include "tcp-face.hpp"
Alexander Afanasyeva9034b02014-01-26 18:32:02 -08009
10namespace ndn {
11
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080012using namespace boost::asio;
13
14TcpChannel::TcpChannel(io_service& ioService,
15 const tcp::Endpoint& localEndpoint)
16 : m_ioService(ioService)
17 , m_localEndpoint(localEndpoint)
Alexander Afanasyeva9034b02014-01-26 18:32:02 -080018{
19}
20
21void
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080022TcpChannel::listen(int backlog/* = tcp::acceptor::max_connections*/)
Alexander Afanasyeva9034b02014-01-26 18:32:02 -080023{
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080024 m_acceptor = make_shared<ip::tcp::acceptor>(boost::ref(m_ioService));
25 m_acceptor->open(m_localEndpoint.protocol());
26 m_acceptor->set_option(ip::tcp::acceptor::reuse_address(true));
27 m_acceptor->bind(m_localEndpoint);
28 m_acceptor->listen(backlog);
29
30 shared_ptr<ip::tcp::socket> clientSocket =
31 make_shared<ip::tcp::socket>(boost::ref(m_ioService));
32 m_acceptor->async_accept(*clientSocket,
33 bind(&TcpChannel::handleConnection, this,
34 _1, clientSocket));
Alexander Afanasyeva9034b02014-01-26 18:32:02 -080035}
36
37void
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080038TcpChannel::connect(const tcp::Endpoint& remoteEndpoint,
39 const time::Duration& timeout/* = time::seconds(4)*/)
Alexander Afanasyeva9034b02014-01-26 18:32:02 -080040{
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080041 shared_ptr<ip::tcp::socket> clientSocket =
42 make_shared<ip::tcp::socket>(boost::ref(m_ioService));
43
44 shared_ptr<monotonic_deadline_timer> connectTimeoutTimer =
45 make_shared<monotonic_deadline_timer>(boost::ref(m_ioService));
46
47 // not sure if it works. This will bind to something...
48 // Do we need reuse here too?
49 clientSocket->bind(m_localEndpoint);
50
51 clientSocket->async_connect(remoteEndpoint,
52 bind(&TcpChannel::handleSuccessfulConnect, this,
53 _1, clientSocket, connectTimeoutTimer));
54
55 connectTimeoutTimer->expires_from_now(timeout);
56 connectTimeoutTimer->async_wait(bind(&TcpChannel::handleFailedConnect, this,
57 _1, clientSocket, connectTimeoutTimer));
Alexander Afanasyeva9034b02014-01-26 18:32:02 -080058}
59
Alexander Afanasyev8ad71ba2014-01-27 00:07:14 -080060void
61TcpChannel::connect(const std::string& remoteHost, const std::string& remotePort,
62 const time::Duration& timeout/* = time::seconds(4)*/)
63{
64 shared_ptr<ip::tcp::socket> clientSocket =
65 make_shared<ip::tcp::socket>(boost::ref(m_ioService));
66
67 shared_ptr<monotonic_deadline_timer> connectTimeoutTimer =
68 make_shared<monotonic_deadline_timer>(boost::ref(m_ioService));
69
70 // not sure if it works. This will bind to something...
71 // Do we need reuse here too?
72 clientSocket->bind(m_localEndpoint);
73
74 ip::tcp::resolver::query query(remoteHost, remotePort);
75 shared_ptr<ip::tcp::resolver> resolver =
76 make_shared<ip::tcp::resolver>(boost::ref(m_ioService));
77
78 resolver->async_resolve(query,
79 bind(&TcpChannel::handleEndpointResoution, this, _1, _2,
80 clientSocket, connectTimeoutTimer));
81
82 connectTimeoutTimer->expires_from_now(timeout);
83 connectTimeoutTimer->async_wait(bind(&TcpChannel::handleFailedConnect, this,
84 _1, clientSocket, connectTimeoutTimer));
85}
86
87
88void
89TcpChannel::handleConnection(const boost::system::error_code& error,
90 const shared_ptr<ip::tcp::socket>& socket)
91{
92 if (error) {
93 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
94 return;
95
96 /// \todo Log the error
97 onConnectFailed("Connect to remote endpoint failed: " +
98 error.category().message(error.value()));
99 return;
100 }
101
102 /**
103 * \todo Either remove FaceId from here or set it here to some real value
104 */
105 shared_ptr<TcpFace> face = make_shared<TcpFace>(1, boost::cref(socket));
106
107 // what's next?
108}
109
110void
111TcpChannel::handleSuccessfulConnect(const boost::system::error_code& error,
112 const shared_ptr<ip::tcp::socket>& socket,
113 const shared_ptr<monotonic_deadline_timer>& timer)
114{
115 timer->cancel();
116
117 if (error) {
118 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
119 return;
120
121 socket->close();
122 onConnectFailed("Connect to remote endpoint failed: " +
123 error.category().message(error.value()));
124 return;
125 }
126
127 handleConnection(error, socket);
128}
129
130void
131TcpChannel::handleFailedConnect(const boost::system::error_code& error,
132 const shared_ptr<ip::tcp::socket>& socket,
133 const shared_ptr<monotonic_deadline_timer>& timer)
134{
135 if (error) { // e.g., cancelled
136 return;
137 }
138
139 onConnectFailed("Connect to remote endpoint timed out: " +
140 error.category().message(error.value()));
141 socket->close(); // abort the connection
142}
143
144void
145TcpChannel::handleEndpointResoution(const boost::system::error_code& error,
146 ip::tcp::resolver::iterator remoteEndpoint,
147 const shared_ptr<boost::asio::ip::tcp::socket>& socket,
148 const shared_ptr<boost::asio::monotonic_deadline_timer>& timer)
149{
150 if (error ||
151 remoteEndpoint == ip::tcp::resolver::iterator())
152 {
153 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
154 return;
155
156 socket->close();
157 timer->cancel();
158 onConnectFailed("Remote endpoint hostname or port cannot be resolved: " +
159 error.category().message(error.value()));
160 return;
161 }
162
163 // got endpoint, now trying to connect (only try the first resolution option)
164 socket->async_connect(*remoteEndpoint,
165 bind(&TcpChannel::handleSuccessfulConnect, this,
166 _1, socket, timer));
167}
168
169
Alexander Afanasyeva9034b02014-01-26 18:32:02 -0800170} // namespace ndn