NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.5: NDN, CCN, CCNx, content centric networks
API Documentation
websocket-channel.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2014-2018, Regents of the University of California,
4  * 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-channel.hpp"
27 #include "generic-link-service.hpp"
28 #include "websocket-transport.hpp"
29 #include "core/global-io.hpp"
30 
31 namespace nfd {
32 namespace face {
33 
35 
37  : m_localEndpoint(localEndpoint)
38  , m_pingInterval(10_s)
39 {
40  setUri(FaceUri(m_localEndpoint, "ws"));
41  NFD_LOG_CHAN_INFO("Creating channel");
42 
43  // Be quiet
44  m_server.clear_access_channels(websocketpp::log::alevel::all);
45  m_server.clear_error_channels(websocketpp::log::elevel::all);
46 
47  // Setup WebSocket server
48  m_server.init_asio(&getGlobalIoService());
49  m_server.set_tcp_pre_bind_handler([isV6 = m_localEndpoint.address().is_v6()] (const auto& acceptor) {
50  if (isV6) {
51  acceptor->set_option(boost::asio::ip::v6_only(true));
52  }
53  return websocketpp::lib::error_code{};
54  });
55  m_server.set_open_handler(bind(&WebSocketChannel::handleOpen, this, _1));
56  m_server.set_close_handler(bind(&WebSocketChannel::handleClose, this, _1));
57  m_server.set_message_handler(bind(&WebSocketChannel::handleMessage, this, _1, _2));
58 
59  // Detect disconnections using ping-pong messages
60  m_server.set_pong_handler(bind(&WebSocketChannel::handlePong, this, _1));
61  m_server.set_pong_timeout_handler(bind(&WebSocketChannel::handlePongTimeout, this, _1));
62 
63  // Always set SO_REUSEADDR flag
64  m_server.set_reuse_addr(true);
65 }
66 
67 void
68 WebSocketChannel::setPingInterval(time::milliseconds interval)
69 {
70  BOOST_ASSERT(!m_server.is_listening());
71 
72  m_pingInterval = interval;
73 }
74 
75 void
76 WebSocketChannel::setPongTimeout(time::milliseconds timeout)
77 {
78  BOOST_ASSERT(!m_server.is_listening());
79 
80  m_server.set_pong_timeout(static_cast<long>(timeout.count()));
81 }
82 
83 void
84 WebSocketChannel::handlePongTimeout(websocketpp::connection_hdl hdl)
85 {
86  auto it = m_channelFaces.find(hdl);
87  if (it != m_channelFaces.end()) {
88  static_cast<WebSocketTransport*>(it->second->getTransport())->handlePongTimeout();
89  }
90  else {
91  NFD_LOG_CHAN_WARN("Pong timeout on unknown transport");
92  }
93 }
94 
95 void
96 WebSocketChannel::handlePong(websocketpp::connection_hdl hdl)
97 {
98  auto it = m_channelFaces.find(hdl);
99  if (it != m_channelFaces.end()) {
100  static_cast<WebSocketTransport*>(it->second->getTransport())->handlePong();
101  }
102  else {
103  NFD_LOG_CHAN_WARN("Pong received on unknown transport");
104  }
105 }
106 
107 void
108 WebSocketChannel::handleMessage(websocketpp::connection_hdl hdl,
109  websocket::Server::message_ptr msg)
110 {
111  auto it = m_channelFaces.find(hdl);
112  if (it != m_channelFaces.end()) {
113  static_cast<WebSocketTransport*>(it->second->getTransport())->receiveMessage(msg->get_payload());
114  }
115  else {
116  NFD_LOG_CHAN_WARN("Message received on unknown transport");
117  }
118 }
119 
120 void
121 WebSocketChannel::handleOpen(websocketpp::connection_hdl hdl)
122 {
123  NFD_LOG_CHAN_TRACE("Incoming connection from " << m_server.get_con_from_hdl(hdl)->get_remote_endpoint());
124 
125  auto linkService = make_unique<GenericLinkService>();
126  auto transport = make_unique<WebSocketTransport>(hdl, std::ref(m_server), m_pingInterval);
127  auto face = make_shared<Face>(std::move(linkService), std::move(transport));
128 
129  BOOST_ASSERT(m_channelFaces.count(hdl) == 0);
130  m_channelFaces[hdl] = face;
131  connectFaceClosedSignal(*face, [this, hdl] { m_channelFaces.erase(hdl); });
132 
133  m_onFaceCreatedCallback(face);
134 }
135 
136 void
137 WebSocketChannel::handleClose(websocketpp::connection_hdl hdl)
138 {
139  auto it = m_channelFaces.find(hdl);
140  if (it != m_channelFaces.end()) {
141  it->second->close();
142  }
143  else {
144  NFD_LOG_CHAN_WARN("Close on unknown transport");
145  }
146 }
147 
148 void
150 {
151  if (isListening()) {
152  NFD_LOG_CHAN_WARN("Already listening");
153  return;
154  }
155 
156  m_onFaceCreatedCallback = onFaceCreated;
157 
158  m_server.listen(m_localEndpoint);
159  m_server.start_accept();
160  NFD_LOG_CHAN_DEBUG("Started listening");
161 }
162 
163 } // namespace face
164 } // namespace nfd
void listen(const FaceCreatedCallback &onFaceCreated)
Enable listening on the local endpoint, accept connections, and create faces when remote host makes a...
void setUri(const FaceUri &uri)
Definition: channel.cpp:34
Class implementing WebSocket-based channel to create faces.
detail::SimulatorIo & getGlobalIoService()
Definition: global-io.cpp:48
std::function< void(const shared_ptr< Face > &face)> FaceCreatedCallback
Prototype for the callback that is invoked when a face is created (in response to an incoming connect...
Definition: channel.hpp:40
void connectFaceClosedSignal(Face &face, const std::function< void()> &f)
invokes a callback when the face is closed
Definition: channel.cpp:40
#define NFD_LOG_CHAN_DEBUG(msg)
Log a message at DEBUG level.
Definition: channel-log.hpp:49
WebSocketChannel(const websocket::Endpoint &localEndpoint)
Create WebSocket channel for the local endpoint.
Copyright (c) 2011-2015 Regents of the University of California.
Definition: ndn-common.hpp:40
#define NFD_LOG_CHAN_INFO(msg)
Log a message at INFO level.
Definition: channel-log.hpp:52
#define NFD_LOG_CHAN_TRACE(msg)
Log a message at TRACE level.
Definition: channel-log.hpp:46
#define NFD_LOG_CHAN_WARN(msg)
Log a message at WARN level.
Definition: channel-log.hpp:55
represents the underlying protocol and address used by a Face
Definition: face-uri.hpp:44
bool isListening() const override
Returns whether the channel is listening.
boost::asio::ip::tcp::endpoint Endpoint
#define NFD_LOG_INIT(name)
Definition: logger.hpp:31