NFD: Named Data Networking Forwarding Daemon 24.07-28-gdcc0e6e0
Loading...
Searching...
No Matches
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-2022, 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 "face.hpp"
30#include "common/global.hpp"
31
32namespace nfd::face {
33
34NFD_LOG_INIT(WebSocketChannel);
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(std::bind(&WebSocketChannel::handleOpen, this, _1));
56 m_server.set_close_handler(std::bind(&WebSocketChannel::handleClose, this, _1));
57 m_server.set_message_handler(std::bind(&WebSocketChannel::handleMessage, this, _1, _2));
58
59 // Detect disconnections using ping-pong messages
60 m_server.set_pong_handler(std::bind(&WebSocketChannel::handlePong, this, _1));
61 m_server.set_pong_timeout_handler(std::bind(&WebSocketChannel::handlePongTimeout, this, _1));
62
63 // Always set SO_REUSEADDR flag
64 m_server.set_reuse_addr(true);
65}
66
67void
68WebSocketChannel::setPingInterval(time::milliseconds interval)
69{
70 BOOST_ASSERT(!m_server.is_listening());
71
72 m_pingInterval = interval;
73}
74
75void
76WebSocketChannel::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
83void
84WebSocketChannel::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
95void
96WebSocketChannel::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
107void
108WebSocketChannel::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
120void
121WebSocketChannel::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, m_server, m_pingInterval);
127 auto face = make_shared<Face>(std::move(linkService), std::move(transport));
128 face->setChannel(weak_from_this());
129
130 BOOST_ASSERT(m_channelFaces.count(hdl) == 0);
131 m_channelFaces[hdl] = face;
132 connectFaceClosedSignal(*face, [this, hdl] { m_channelFaces.erase(hdl); });
133
134 m_onFaceCreatedCallback(face);
135}
136
137void
138WebSocketChannel::handleClose(websocketpp::connection_hdl hdl)
139{
140 auto it = m_channelFaces.find(hdl);
141 if (it != m_channelFaces.end()) {
142 it->second->close();
143 }
144 else {
145 NFD_LOG_CHAN_WARN("Close on unknown transport");
146 }
147}
148
149void
150WebSocketChannel::listen(const FaceCreatedCallback& onFaceCreated)
151{
152 if (isListening()) {
153 NFD_LOG_CHAN_WARN("Already listening");
154 return;
155 }
156
157 m_onFaceCreatedCallback = onFaceCreated;
158
159 m_server.listen(m_localEndpoint);
160 m_server.start_accept();
161 NFD_LOG_CHAN_DEBUG("Started listening");
162}
163
164} // namespace nfd::face
void setUri(const FaceUri &uri) noexcept
Definition channel.cpp:34
WebSocketChannel(const websocket::Endpoint &localEndpoint)
Create a WebSocket channel for the given localEndpoint.
#define NFD_LOG_CHAN_DEBUG(msg)
Log a message at DEBUG level.
#define NFD_LOG_CHAN_INFO(msg)
Log a message at INFO level.
#define NFD_LOG_CHAN_WARN(msg)
Log a message at WARN level.
#define NFD_LOG_CHAN_TRACE(msg)
Log a message at TRACE level.
#define NFD_LOG_INIT(name)
Definition logger.hpp:31
std::function< void(const shared_ptr< Face > &)> FaceCreatedCallback
Prototype for the callback that is invoked when a face is created (in response to an incoming connect...
Definition channel.hpp:90
void connectFaceClosedSignal(Face &face, std::function< void()> f)
Invokes a callback when a face is closed.
Definition channel.cpp:46
boost::asio::ip::tcp::endpoint Endpoint
boost::asio::io_context & getGlobalIoService()
Returns the global io_context instance for the calling thread.
Definition global.cpp:36