face: WebSocketTransport
Change-Id: I28db9cd6f828e4a9fe5895bb7a6152cca5baa9fc
Refs: #3169, #3160
diff --git a/daemon/face/websocket-channel.cpp b/daemon/face/websocket-channel.cpp
index 7997b1e..520bb7d 100644
--- a/daemon/face/websocket-channel.cpp
+++ b/daemon/face/websocket-channel.cpp
@@ -24,10 +24,9 @@
*/
#include "websocket-channel.hpp"
+#include "generic-link-service.hpp"
+#include "websocket-transport.hpp"
#include "core/global-io.hpp"
-#include "core/scheduler.hpp"
-
-#include <boost/date_time/posix_time/posix_time.hpp>
namespace nfd {
@@ -35,23 +34,23 @@
WebSocketChannel::WebSocketChannel(const websocket::Endpoint& localEndpoint)
: m_localEndpoint(localEndpoint)
- , m_isListening(false)
, m_pingInterval(10000)
{
setUri(FaceUri(m_localEndpoint, "ws"));
- // Setup WebSocket server
+ // Be quiet
m_server.clear_access_channels(websocketpp::log::alevel::all);
- m_server.clear_error_channels(websocketpp::log::alevel::all);
+ m_server.clear_error_channels(websocketpp::log::elevel::all);
- m_server.set_message_handler(bind(&WebSocketChannel::handleMessage, this, _1, _2));
+ // Setup WebSocket server
+ m_server.init_asio(&getGlobalIoService());
m_server.set_open_handler(bind(&WebSocketChannel::handleOpen, this, _1));
m_server.set_close_handler(bind(&WebSocketChannel::handleClose, this, _1));
- m_server.init_asio(&getGlobalIoService());
+ m_server.set_message_handler(bind(&WebSocketChannel::handleMessage, this, _1, _2));
// Detect disconnections using ping-pong messages
- m_server.set_pong_handler(bind(&WebSocketChannel::handlePong, this, _1, _2));
- m_server.set_pong_timeout_handler(bind(&WebSocketChannel::handlePongTimeout, this, _1, _2));
+ m_server.set_pong_handler(bind(&WebSocketChannel::handlePong, this, _1));
+ m_server.set_pong_timeout_handler(bind(&WebSocketChannel::handlePongTimeout, this, _1));
// Always set SO_REUSEADDR flag
m_server.set_reuse_addr(true);
@@ -60,32 +59,40 @@
void
WebSocketChannel::setPingInterval(time::milliseconds interval)
{
+ BOOST_ASSERT(!m_server.is_listening());
+
m_pingInterval = interval;
}
void
WebSocketChannel::setPongTimeout(time::milliseconds timeout)
{
+ BOOST_ASSERT(!m_server.is_listening());
+
m_server.set_pong_timeout(static_cast<long>(timeout.count()));
}
void
-WebSocketChannel::handlePongTimeout(websocketpp::connection_hdl hdl, std::string msg)
+WebSocketChannel::handlePongTimeout(websocketpp::connection_hdl hdl)
{
auto it = m_channelFaces.find(hdl);
if (it != m_channelFaces.end()) {
- NFD_LOG_TRACE(__func__ << ": " << it->second->getRemoteUri());
- it->second->close();
- m_channelFaces.erase(it);
+ static_cast<face::WebSocketTransport*>(it->second->getLpFace()->getTransport())->handlePongTimeout();
+ }
+ else {
+ NFD_LOG_WARN("Pong timeout on unknown transport");
}
}
void
-WebSocketChannel::handlePong(websocketpp::connection_hdl hdl, std::string msg)
+WebSocketChannel::handlePong(websocketpp::connection_hdl hdl)
{
auto it = m_channelFaces.find(hdl);
if (it != m_channelFaces.end()) {
- NFD_LOG_TRACE("Pong from " << it->second->getRemoteUri());
+ static_cast<face::WebSocketTransport*>(it->second->getLpFace()->getTransport())->handlePong();
+ }
+ else {
+ NFD_LOG_WARN("Pong received on unknown transport");
}
}
@@ -95,62 +102,30 @@
{
auto it = m_channelFaces.find(hdl);
if (it != m_channelFaces.end()) {
- it->second->handleReceive(msg->get_payload());
+ static_cast<face::WebSocketTransport*>(it->second->getLpFace()->getTransport())->receiveMessage(msg->get_payload());
+ }
+ else {
+ NFD_LOG_WARN("Message received on unknown transport");
}
}
void
WebSocketChannel::handleOpen(websocketpp::connection_hdl hdl)
{
- try {
- std::string remote = "wsclient://" + m_server.get_con_from_hdl(hdl)->get_remote_endpoint();
- auto face = make_shared<WebSocketFace>(FaceUri(remote), this->getUri(),
- hdl, ref(m_server));
- m_onFaceCreatedCallback(face);
- m_channelFaces[hdl] = face;
- // Schedule ping message
- scheduler::EventId pingEvent = scheduler::schedule(m_pingInterval,
- bind(&WebSocketChannel::sendPing,
- this, hdl));
- face->setPingEventId(pingEvent);
- }
- catch (const FaceUri::Error& e) {
- NFD_LOG_WARN(e.what());
- websocketpp::lib::error_code ec;
- m_server.close(hdl, websocketpp::close::status::normal, "closed by channel", ec);
- // ignore error on close
- }
- catch (const websocketpp::exception& e) {
- NFD_LOG_WARN("Cannot get remote connection: " << e.what());
- websocketpp::lib::error_code ec;
- m_server.close(hdl, websocketpp::close::status::normal, "closed by channel", ec);
- // ignore error on close
- }
-}
+ auto linkService = make_unique<face::GenericLinkService>();
+ auto transport = make_unique<face::WebSocketTransport>(hdl, ref(m_server), m_pingInterval);
+ auto lpFace = make_unique<face::LpFace>(std::move(linkService), std::move(transport));
+ auto face = make_shared<face::LpFaceWrapper>(std::move(lpFace));
-void
-WebSocketChannel::sendPing(websocketpp::connection_hdl hdl)
-{
- auto it = m_channelFaces.find(hdl);
- if (it != m_channelFaces.end()) {
- NFD_LOG_TRACE("Sending ping to " << it->second->getRemoteUri());
-
- websocketpp::lib::error_code ec;
- m_server.ping(hdl, "NFD-WebSocket", ec);
- if (ec)
- {
- NFD_LOG_WARN("Failed to ping " << it->second->getRemoteUri() << ": " << ec.message());
- it->second->close();
- m_channelFaces.erase(it);
- return;
+ face->getLpFace()->afterStateChange.connect(
+ [this, hdl] (face::FaceState oldState, face::FaceState newState) {
+ if (newState == face::FaceState::CLOSED) {
+ m_channelFaces.erase(hdl);
}
+ });
+ m_channelFaces[hdl] = face;
- // Schedule next ping message
- scheduler::EventId pingEvent = scheduler::schedule(m_pingInterval,
- bind(&WebSocketChannel::sendPing,
- this, hdl));
- it->second->setPingEventId(pingEvent);
- }
+ m_onFaceCreatedCallback(face);
}
void
@@ -158,20 +133,20 @@
{
auto it = m_channelFaces.find(hdl);
if (it != m_channelFaces.end()) {
- NFD_LOG_TRACE(__func__ << ": " << it->second->getRemoteUri());
- it->second->close();
- m_channelFaces.erase(it);
+ it->second->getLpFace()->close();
+ }
+ else {
+ NFD_LOG_WARN("Close on unknown transport");
}
}
void
WebSocketChannel::listen(const FaceCreatedCallback& onFaceCreated)
{
- if (isListening()) {
+ if (m_server.is_listening()) {
NFD_LOG_WARN("[" << m_localEndpoint << "] Already listening");
return;
}
- m_isListening = true;
m_onFaceCreatedCallback = onFaceCreated;
m_server.listen(m_localEndpoint);
diff --git a/daemon/face/websocket-channel.hpp b/daemon/face/websocket-channel.hpp
index 027085c..47eda8c 100644
--- a/daemon/face/websocket-channel.hpp
+++ b/daemon/face/websocket-channel.hpp
@@ -27,7 +27,8 @@
#define NFD_DAEMON_FACE_WEBSOCKET_CHANNEL_HPP
#include "channel.hpp"
-#include "websocket-face.hpp"
+#include "lp-face-wrapper.hpp"
+#include "websocketpp.hpp"
namespace nfd {
@@ -46,9 +47,7 @@
*
* To enable creation of faces upon incoming connections,
* one needs to explicitly call WebSocketChannel::listen method.
- * The created socket is bound to the localEndpoint.
- *
- * \throw WebSocketChannel::Error if bind on the socket fails
+ * The created channel is bound to the localEndpoint.
*/
explicit
WebSocketChannel(const websocket::Endpoint& localEndpoint);
@@ -56,9 +55,8 @@
/**
* \brief Enable listening on the local endpoint, accept connections,
* and create faces when remote host makes a connection
- * \param onFaceCreated Callback to notify successful creation of the face
*
- * \throws WebSocketChannel::Error if called multiple times
+ * \param onFaceCreated Callback to notify successful creation of a face
*/
void
listen(const FaceCreatedCallback& onFaceCreated);
@@ -73,24 +71,26 @@
isListening() const;
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
+ /** \pre listen hasn't been invoked
+ */
void
setPingInterval(time::milliseconds interval);
+ /** \pre listen hasn't been invoked
+ */
void
setPongTimeout(time::milliseconds timeout);
+ void
+ handlePong(websocketpp::connection_hdl hdl);
+
+ void
+ handlePongTimeout(websocketpp::connection_hdl hdl);
+
private:
void
- sendPing(websocketpp::connection_hdl hdl);
-
- void
- handlePong(websocketpp::connection_hdl hdl, std::string msg);
-
- void
- handlePongTimeout(websocketpp::connection_hdl hdl, std::string msg);
-
- void
- handleMessage(websocketpp::connection_hdl hdl, websocket::Server::message_ptr msg);
+ handleMessage(websocketpp::connection_hdl hdl,
+ websocket::Server::message_ptr msg);
void
handleOpen(websocketpp::connection_hdl hdl);
@@ -102,26 +102,17 @@
websocket::Endpoint m_localEndpoint;
websocket::Server m_server;
- std::map<websocketpp::connection_hdl, shared_ptr<WebSocketFace>,
+ std::map<websocketpp::connection_hdl, shared_ptr<face::LpFaceWrapper>,
std::owner_less<websocketpp::connection_hdl>> m_channelFaces;
- /**
- * Callback for face creation
- */
FaceCreatedCallback m_onFaceCreatedCallback;
-
- /**
- * \brief If true, it means the function listen has already been called
- */
- bool m_isListening;
-
time::milliseconds m_pingInterval;
};
inline bool
WebSocketChannel::isListening() const
{
- return m_isListening;
+ return m_server.is_listening();
}
} // namespace nfd
diff --git a/daemon/face/websocket-face.cpp b/daemon/face/websocket-face.cpp
deleted file mode 100644
index 3b94e6e..0000000
--- a/daemon/face/websocket-face.cpp
+++ /dev/null
@@ -1,131 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014-2015, Regents of the University of California,
- * Arizona Board of Regents,
- * Colorado State University,
- * University Pierre & Marie Curie, Sorbonne University,
- * Washington University in St. Louis,
- * Beijing Institute of Technology,
- * The University of Memphis.
- *
- * This file is part of NFD (Named Data Networking Forwarding Daemon).
- * See AUTHORS.md for complete list of NFD authors and contributors.
- *
- * NFD is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- *
- * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "websocket-face.hpp"
-
-namespace nfd {
-
-NFD_LOG_INIT("WebSocketFace");
-
-WebSocketFace::WebSocketFace(const FaceUri& remoteUri, const FaceUri& localUri,
- websocketpp::connection_hdl hdl,
- websocket::Server& server)
- : Face(remoteUri, localUri)
- , m_handle(hdl)
- , m_server(server)
- , m_closed(false)
-{
- NFD_LOG_FACE_INFO("Creating face");
- this->setPersistency(ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
-}
-
-void
-WebSocketFace::sendInterest(const Interest& interest)
-{
- if (m_closed)
- return;
-
- NFD_LOG_FACE_TRACE(__func__);
-
- this->emitSignal(onSendInterest, interest);
-
- const Block& payload = interest.wireEncode();
- this->getMutableCounters().getNOutBytes() += payload.size();
-
- websocketpp::lib::error_code ec;
- m_server.send(m_handle, payload.wire(), payload.size(),
- websocketpp::frame::opcode::binary, ec);
- if (ec)
- NFD_LOG_FACE_WARN("Failed to send Interest: " << ec.message());
-}
-
-void
-WebSocketFace::sendData(const Data& data)
-{
- if (m_closed)
- return;
-
- NFD_LOG_FACE_TRACE(__func__);
-
- this->emitSignal(onSendData, data);
-
- const Block& payload = data.wireEncode();
- this->getMutableCounters().getNOutBytes() += payload.size();
-
- websocketpp::lib::error_code ec;
- m_server.send(m_handle, payload.wire(), payload.size(),
- websocketpp::frame::opcode::binary, ec);
- if (ec)
- NFD_LOG_FACE_WARN("Failed to send Data: " << ec.message());
-}
-
-void
-WebSocketFace::close()
-{
- if (m_closed)
- return;
-
- NFD_LOG_FACE_INFO("Closing face");
-
- m_closed = true;
- scheduler::cancel(m_pingEventId);
- websocketpp::lib::error_code ec;
- m_server.close(m_handle, websocketpp::close::status::normal, "closed by nfd", ec);
- // ignore error on close
- fail("Face closed");
-}
-
-void
-WebSocketFace::handleReceive(const std::string& msg)
-{
- // Copy message into Face internal buffer
- if (msg.size() > ndn::MAX_NDN_PACKET_SIZE)
- {
- NFD_LOG_FACE_WARN("Received WebSocket message is too big (" << msg.size() << " bytes)");
- return;
- }
-
- NFD_LOG_FACE_TRACE("Received: " << msg.size() << " bytes");
- this->getMutableCounters().getNInBytes() += msg.size();
-
- // Try to parse message data
- bool isOk = false;
- Block element;
- std::tie(isOk, element) = Block::fromBuffer(reinterpret_cast<const uint8_t*>(msg.c_str()),
- msg.size());
- if (!isOk)
- {
- NFD_LOG_FACE_WARN("Received block is invalid or too large to process");
- return;
- }
-
- if (!this->decodeAndDispatchInput(element))
- {
- NFD_LOG_FACE_WARN("Received unrecognized TLV block of type " << element.type());
- // ignore unknown packet and proceed
- }
-}
-
-} // namespace nfd
diff --git a/daemon/face/websocket-face.hpp b/daemon/face/websocket-face.hpp
deleted file mode 100644
index 3c7fbf1..0000000
--- a/daemon/face/websocket-face.hpp
+++ /dev/null
@@ -1,86 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014-2015, Regents of the University of California,
- * Arizona Board of Regents,
- * Colorado State University,
- * University Pierre & Marie Curie, Sorbonne University,
- * Washington University in St. Louis,
- * Beijing Institute of Technology,
- * The University of Memphis.
- *
- * This file is part of NFD (Named Data Networking Forwarding Daemon).
- * See AUTHORS.md for complete list of NFD authors and contributors.
- *
- * NFD is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- *
- * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef NFD_DAEMON_FACE_WEBSOCKET_FACE_HPP
-#define NFD_DAEMON_FACE_WEBSOCKET_FACE_HPP
-
-#include "face.hpp"
-#include "core/scheduler.hpp"
-
-#ifndef HAVE_WEBSOCKET
-#error "Cannot include this file when WebSocket support is not enabled"
-#endif // HAVE_WEBSOCKET
-
-#include "websocketpp.hpp"
-
-namespace nfd {
-
-namespace websocket {
-typedef websocketpp::server<websocketpp::config::asio> Server;
-} // namespace websocket
-
-/**
- * \brief Implementation of Face abstraction that uses WebSocket
- * as underlying transport mechanism
- */
-class WebSocketFace : public Face
-{
-public:
- WebSocketFace(const FaceUri& remoteUri, const FaceUri& localUri,
- websocketpp::connection_hdl hdl, websocket::Server& server);
-
- // from Face
- void
- sendInterest(const Interest& interest) DECL_OVERRIDE;
-
- void
- sendData(const Data& data) DECL_OVERRIDE;
-
- void
- close() DECL_OVERRIDE;
-
- void
- setPingEventId(scheduler::EventId& id)
- {
- m_pingEventId = id;
- }
-
-protected:
- // friend because it needs to invoke protected handleReceive
- friend class WebSocketChannel;
-
- void
- handleReceive(const std::string& msg);
-
-private:
- websocketpp::connection_hdl m_handle;
- websocket::Server& m_server;
- scheduler::EventId m_pingEventId;
- bool m_closed;
-};
-
-} // namespace nfd
-
-#endif // NFD_DAEMON_FACE_WEBSOCKET_FACE_HPP
diff --git a/daemon/face/websocket-transport.cpp b/daemon/face/websocket-transport.cpp
new file mode 100644
index 0000000..4fbed81
--- /dev/null
+++ b/daemon/face/websocket-transport.cpp
@@ -0,0 +1,162 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2015, Regents of the University of California,
+ * Arizona Board of Regents,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University,
+ * Washington University in St. Louis,
+ * Beijing Institute of Technology,
+ * The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "websocket-transport.hpp"
+
+namespace nfd {
+namespace face {
+
+NFD_LOG_INIT("WebSocketTransport");
+
+WebSocketTransport::WebSocketTransport(websocketpp::connection_hdl hdl,
+ websocket::Server& server,
+ time::milliseconds pingInterval)
+ : m_handle(hdl)
+ , m_server(server)
+ , m_pingInterval(pingInterval)
+{
+ const auto& sock = m_server.get_con_from_hdl(hdl)->get_socket();
+ this->setLocalUri(FaceUri(sock.local_endpoint(), "ws"));
+ this->setRemoteUri(FaceUri(sock.remote_endpoint(), "wsclient"));
+
+ if (sock.local_endpoint().address().is_loopback() &&
+ sock.remote_endpoint().address().is_loopback())
+ this->setScope(ndn::nfd::FACE_SCOPE_LOCAL);
+ else
+ this->setScope(ndn::nfd::FACE_SCOPE_NON_LOCAL);
+
+ this->setPersistency(ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
+ this->setLinkType(ndn::nfd::LINK_TYPE_POINT_TO_POINT);
+ this->setMtu(MTU_UNLIMITED);
+
+ this->schedulePing();
+
+ NFD_LOG_FACE_INFO("Creating transport");
+}
+
+void WebSocketTransport::beforeChangePersistency(ndn::nfd::FacePersistency newPersistency)
+{
+ if (newPersistency != ndn::nfd::FACE_PERSISTENCY_ON_DEMAND) {
+ BOOST_THROW_EXCEPTION(
+ std::invalid_argument("WebSocketTransport supports only FACE_PERSISTENCY_ON_DEMAND"));
+ }
+}
+
+void
+WebSocketTransport::doSend(Transport::Packet&& packet)
+{
+ NFD_LOG_FACE_TRACE(__func__);
+
+ websocketpp::lib::error_code error;
+ m_server.send(m_handle, packet.packet.wire(), packet.packet.size(),
+ websocketpp::frame::opcode::binary, error);
+ if (error)
+ return processErrorCode(error);
+
+ NFD_LOG_FACE_TRACE("Successfully sent: " << packet.packet.size() << " bytes");
+}
+
+void
+WebSocketTransport::receiveMessage(const std::string& msg)
+{
+ NFD_LOG_FACE_TRACE("Received: " << msg.size() << " bytes");
+
+ bool isOk = false;
+ Block element;
+ std::tie(isOk, element) = Block::fromBuffer(reinterpret_cast<const uint8_t*>(msg.c_str()), msg.size());
+ if (!isOk) {
+ NFD_LOG_FACE_WARN("Failed to parse message payload");
+ return;
+ }
+
+ this->receive(Transport::Packet(std::move(element)));
+}
+
+void
+WebSocketTransport::schedulePing()
+{
+ m_pingEventId = scheduler::schedule(m_pingInterval, bind(&WebSocketTransport::sendPing, this));
+}
+
+void
+WebSocketTransport::sendPing()
+{
+ NFD_LOG_FACE_TRACE(__func__);
+
+ websocketpp::lib::error_code error;
+ m_server.ping(m_handle, "NFD-WebSocket", error);
+ if (error)
+ return processErrorCode(error);
+
+ this->schedulePing();
+}
+
+void
+WebSocketTransport::handlePong()
+{
+ NFD_LOG_FACE_TRACE(__func__);
+}
+
+void
+WebSocketTransport::handlePongTimeout()
+{
+ NFD_LOG_FACE_WARN(__func__);
+ this->setState(TransportState::FAILED);
+ doClose();
+}
+
+void
+WebSocketTransport::processErrorCode(const websocketpp::lib::error_code& error)
+{
+ NFD_LOG_FACE_TRACE(__func__);
+
+ if (getState() == TransportState::CLOSING ||
+ getState() == TransportState::FAILED ||
+ getState() == TransportState::CLOSED)
+ // transport is shutting down, ignore any errors
+ return;
+
+ NFD_LOG_FACE_WARN("Send or ping operation failed: " << error.message());
+
+ this->setState(TransportState::FAILED);
+ doClose();
+}
+
+void
+WebSocketTransport::doClose()
+{
+ NFD_LOG_FACE_TRACE(__func__);
+
+ m_pingEventId.cancel();
+
+ // use the non-throwing variant and ignore errors, if any
+ websocketpp::lib::error_code error;
+ m_server.close(m_handle, websocketpp::close::status::normal, "closed by NFD", error);
+
+ this->setState(TransportState::CLOSED);
+}
+
+} // namespace face
+} // namespace nfd
diff --git a/daemon/face/websocket-transport.hpp b/daemon/face/websocket-transport.hpp
new file mode 100644
index 0000000..6bfbdc3
--- /dev/null
+++ b/daemon/face/websocket-transport.hpp
@@ -0,0 +1,88 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2015, Regents of the University of California,
+ * Arizona Board of Regents,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University,
+ * Washington University in St. Louis,
+ * Beijing Institute of Technology,
+ * The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NFD_DAEMON_FACE_WEBSOCKET_TRANSPORT_HPP
+#define NFD_DAEMON_FACE_WEBSOCKET_TRANSPORT_HPP
+
+#include "transport.hpp"
+#include "websocketpp.hpp"
+#include "core/scheduler.hpp"
+
+namespace nfd {
+namespace face {
+
+/**
+ * \brief A Transport that communicates on a WebSocket connection
+ */
+class WebSocketTransport : public Transport
+{
+public:
+ WebSocketTransport(websocketpp::connection_hdl hdl,
+ websocket::Server& server,
+ time::milliseconds pingInterval);
+
+ /** \brief Translates a message into a Block
+ * and delivers it to the link service
+ */
+ void
+ receiveMessage(const std::string& msg);
+
+ void
+ handlePong();
+
+ void
+ handlePongTimeout();
+
+protected:
+ virtual void
+ beforeChangePersistency(ndn::nfd::FacePersistency newPersistency) DECL_OVERRIDE;
+
+ virtual void
+ doClose() DECL_OVERRIDE;
+
+private:
+ virtual void
+ doSend(Transport::Packet&& packet) DECL_OVERRIDE;
+
+ void
+ schedulePing();
+
+ void
+ sendPing();
+
+ void
+ processErrorCode(const websocketpp::lib::error_code& error);
+
+private:
+ websocketpp::connection_hdl m_handle;
+ websocket::Server& m_server;
+ time::milliseconds m_pingInterval;
+ scheduler::ScopedEventId m_pingEventId;
+};
+
+} // namespace face
+} // namespace nfd
+
+#endif // NFD_DAEMON_FACE_WEBSOCKET_TRANSPORT_HPP
diff --git a/daemon/face/websocketpp.hpp b/daemon/face/websocketpp.hpp
index f590bd1..35581fe 100644
--- a/daemon/face/websocketpp.hpp
+++ b/daemon/face/websocketpp.hpp
@@ -1,12 +1,12 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2014, Regents of the University of California,
- * Arizona Board of Regents,
- * Colorado State University,
- * University Pierre & Marie Curie, Sorbonne University,
- * Washington University in St. Louis,
- * Beijing Institute of Technology,
- * The University of Memphis
+ * Copyright (c) 2014-2015, Regents of the University of California,
+ * Arizona Board of Regents,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University,
+ * Washington University in St. Louis,
+ * Beijing Institute of Technology,
+ * The University of Memphis.
*
* This file is part of NFD (Named Data Networking Forwarding Daemon).
* See AUTHORS.md for complete list of NFD authors and contributors.
@@ -27,14 +27,25 @@
#define NFD_DAEMON_FACE_WEBSOCKETPP_HPP
#ifndef HAVE_WEBSOCKET
-#error "This file must not be included when WebSocket Face support is disabled"
-#endif
+#error "Cannot include this file when WebSocket support is disabled"
+#endif // HAVE_WEBSOCKET
// suppress websocketpp warnings
#pragma GCC system_header
#pragma clang system_header
+#include <websocketpp/config/asio_no_tls_client.hpp>
+#include <websocketpp/client.hpp>
#include "websocketpp/config/asio_no_tls.hpp"
#include "websocketpp/server.hpp"
+namespace nfd {
+namespace websocket {
+
+typedef websocketpp::client<websocketpp::config::asio_client> Client;
+typedef websocketpp::server<websocketpp::config::asio> Server;
+
+} // namespace websocket
+} // namespace nfd
+
#endif // NFD_DAEMON_FACE_WEBSOCKETPP_HPP