blob: 2fc331c15c209fc1ea89b900d374fc99054cdb05 [file] [log] [blame]
Yukai Tu2d6d5632015-10-26 11:06:02 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Eric Newberry4a4ccfe2016-07-21 22:51:04 -07003 * Copyright (c) 2014-2016, Regents of the University of California,
Yukai Tu2d6d5632015-10-26 11:06:02 -07004 * Arizona Board of Regents,
5 * Colorado State University,
6 * University Pierre & Marie Curie, Sorbonne University,
7 * Washington University in St. Louis,
8 * Beijing Institute of Technology,
9 * The University of Memphis.
10 *
11 * This file is part of NFD (Named Data Networking Forwarding Daemon).
12 * See AUTHORS.md for complete list of NFD authors and contributors.
13 *
14 * NFD is free software: you can redistribute it and/or modify it under the terms
15 * of the GNU General Public License as published by the Free Software Foundation,
16 * either version 3 of the License, or (at your option) any later version.
17 *
18 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
19 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
20 * PURPOSE. See the GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along with
23 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
24 */
25
26#include "websocket-transport.hpp"
27
28namespace nfd {
29namespace face {
30
31NFD_LOG_INIT("WebSocketTransport");
32
Eric Newberry4a4ccfe2016-07-21 22:51:04 -070033static bool
34isLoopback(const boost::asio::ip::address& addr)
35{
36 if (addr.is_loopback()) {
37 return true;
38 }
39 // Workaround for loopback IPv4-mapped IPv6 addresses
40 // see https://svn.boost.org/trac/boost/ticket/9084
41 else if (addr.is_v6()) {
42 auto addr6 = addr.to_v6();
43 if (addr6.is_v4_mapped()) {
44 return addr6.to_v4().is_loopback();
45 }
46 }
47
48 return false;
49}
50
Yukai Tu2d6d5632015-10-26 11:06:02 -070051WebSocketTransport::WebSocketTransport(websocketpp::connection_hdl hdl,
52 websocket::Server& server,
53 time::milliseconds pingInterval)
54 : m_handle(hdl)
55 , m_server(server)
56 , m_pingInterval(pingInterval)
57{
58 const auto& sock = m_server.get_con_from_hdl(hdl)->get_socket();
59 this->setLocalUri(FaceUri(sock.local_endpoint(), "ws"));
60 this->setRemoteUri(FaceUri(sock.remote_endpoint(), "wsclient"));
61
Eric Newberry4a4ccfe2016-07-21 22:51:04 -070062 if (isLoopback(sock.local_endpoint().address()) &&
63 isLoopback(sock.remote_endpoint().address())) {
Yukai Tu2d6d5632015-10-26 11:06:02 -070064 this->setScope(ndn::nfd::FACE_SCOPE_LOCAL);
Eric Newberry4a4ccfe2016-07-21 22:51:04 -070065 }
66 else {
Yukai Tu2d6d5632015-10-26 11:06:02 -070067 this->setScope(ndn::nfd::FACE_SCOPE_NON_LOCAL);
Eric Newberry4a4ccfe2016-07-21 22:51:04 -070068 }
Yukai Tu2d6d5632015-10-26 11:06:02 -070069
70 this->setPersistency(ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
71 this->setLinkType(ndn::nfd::LINK_TYPE_POINT_TO_POINT);
72 this->setMtu(MTU_UNLIMITED);
73
74 this->schedulePing();
75
76 NFD_LOG_FACE_INFO("Creating transport");
77}
78
Davide Pesavento8728a252015-11-06 04:01:22 +010079void
80WebSocketTransport::beforeChangePersistency(ndn::nfd::FacePersistency newPersistency)
Yukai Tu2d6d5632015-10-26 11:06:02 -070081{
82 if (newPersistency != ndn::nfd::FACE_PERSISTENCY_ON_DEMAND) {
83 BOOST_THROW_EXCEPTION(
84 std::invalid_argument("WebSocketTransport supports only FACE_PERSISTENCY_ON_DEMAND"));
85 }
86}
87
88void
89WebSocketTransport::doSend(Transport::Packet&& packet)
90{
91 NFD_LOG_FACE_TRACE(__func__);
92
93 websocketpp::lib::error_code error;
94 m_server.send(m_handle, packet.packet.wire(), packet.packet.size(),
95 websocketpp::frame::opcode::binary, error);
96 if (error)
97 return processErrorCode(error);
98
99 NFD_LOG_FACE_TRACE("Successfully sent: " << packet.packet.size() << " bytes");
100}
101
102void
103WebSocketTransport::receiveMessage(const std::string& msg)
104{
105 NFD_LOG_FACE_TRACE("Received: " << msg.size() << " bytes");
106
107 bool isOk = false;
108 Block element;
109 std::tie(isOk, element) = Block::fromBuffer(reinterpret_cast<const uint8_t*>(msg.c_str()), msg.size());
110 if (!isOk) {
111 NFD_LOG_FACE_WARN("Failed to parse message payload");
112 return;
113 }
114
115 this->receive(Transport::Packet(std::move(element)));
116}
117
118void
119WebSocketTransport::schedulePing()
120{
121 m_pingEventId = scheduler::schedule(m_pingInterval, bind(&WebSocketTransport::sendPing, this));
122}
123
124void
125WebSocketTransport::sendPing()
126{
127 NFD_LOG_FACE_TRACE(__func__);
128
Junxiao Shi57df2882015-11-11 06:12:35 -0700129 ++this->nOutPings;
130
Yukai Tu2d6d5632015-10-26 11:06:02 -0700131 websocketpp::lib::error_code error;
132 m_server.ping(m_handle, "NFD-WebSocket", error);
133 if (error)
134 return processErrorCode(error);
135
136 this->schedulePing();
137}
138
139void
140WebSocketTransport::handlePong()
141{
142 NFD_LOG_FACE_TRACE(__func__);
Junxiao Shi57df2882015-11-11 06:12:35 -0700143
144 ++this->nInPongs;
Yukai Tu2d6d5632015-10-26 11:06:02 -0700145}
146
147void
148WebSocketTransport::handlePongTimeout()
149{
150 NFD_LOG_FACE_WARN(__func__);
151 this->setState(TransportState::FAILED);
152 doClose();
153}
154
155void
156WebSocketTransport::processErrorCode(const websocketpp::lib::error_code& error)
157{
158 NFD_LOG_FACE_TRACE(__func__);
159
160 if (getState() == TransportState::CLOSING ||
161 getState() == TransportState::FAILED ||
162 getState() == TransportState::CLOSED)
163 // transport is shutting down, ignore any errors
164 return;
165
166 NFD_LOG_FACE_WARN("Send or ping operation failed: " << error.message());
167
168 this->setState(TransportState::FAILED);
169 doClose();
170}
171
172void
173WebSocketTransport::doClose()
174{
175 NFD_LOG_FACE_TRACE(__func__);
176
177 m_pingEventId.cancel();
178
179 // use the non-throwing variant and ignore errors, if any
180 websocketpp::lib::error_code error;
181 m_server.close(m_handle, websocketpp::close::status::normal, "closed by NFD", error);
182
183 this->setState(TransportState::CLOSED);
184}
185
186} // namespace face
187} // namespace nfd