face: Implement WebSocket channel, face, and factory.

Change-Id: Ic4dbb1abdbbdbec028746ba14b11be8ab9cc1edb
Refs: #1468
This commit is contained in:
Wentao Shang
2014-04-21 12:01:32 -07:00
committed by Alexander Afanasyev
parent ff489a230a
commit 53df163b62
17 changed files with 886 additions and 5 deletions
+3
View File
@@ -0,0 +1,3 @@
[submodule "websocketpp"]
path = websocketpp
url = https://github.com/zaphoyd/websocketpp.git
+77
View File
@@ -0,0 +1,77 @@
# encoding: utf-8
from waflib import Options, Logs, Errors
from waflib.Configure import conf
import re
def addWebsocketOptions(self, opt):
opt.add_option('--without-websocket', action='store_false', default=True,
dest='with_websocket',
help='Disable WebSocket face support')
setattr(Options.OptionsContext, "addWebsocketOptions", addWebsocketOptions)
@conf
def checkWebsocket(self, **kw):
if not self.options.with_websocket:
return
isMandatory = kw.get('mandatory', True)
self.start_msg('Checking for Websocket includes')
try:
websocketDir = self.path.find_dir('websocketpp/websocketpp')
if not websocketDir:
raise Errors.WafError('Not found')
versionFile = websocketDir.find_node('version.hpp')
if not websocketDir:
raise Errors.WafError('Corrupted: Websocket version file not found')
try:
txt = versionFile.read()
except (OSError, IOError):
raise Errors.WafError('Corrupted: cannot read Websocket version file')
# Looking for the following:
# static int const major_version = 0;
# static int const minor_version = 3;
# static int const patch_version = 0;
version = [None, None, None]
majorVersion = re.compile('^static int const major_version = (\\d+);$', re.M)
version[0] = majorVersion.search(txt)
minorVersion = re.compile('^static int const minor_version = (\\d+);$', re.M)
version[1] = minorVersion.search(txt)
patchVersion = re.compile('^static int const patch_version = (\\d+);$', re.M)
version[2] = patchVersion.search(txt)
if not version[0] or not version[1] or not version[2]:
raise Errors.WafError('Corrupted: cannot detect websocket version')
self.env['WEBSOCKET_VERSION'] = [i.group(1) for i in version]
# todo: version checking, if necessary
self.end_msg('.'.join(self.env['WEBSOCKET_VERSION']))
self.env['HAVE_WEBSOCKET'] = True
self.define('HAVE_WEBSOCKET', 1)
except Errors.WafError as error:
if isMandatory:
self.end_msg(str(error), color='RED')
Logs.warn('If you are using git NFD repository, checkout websocketpp submodule: ')
Logs.warn(' git submodule init && git submodule update')
Logs.warn('Otherwise, manually download and extract websocketpp library:')
Logs.warn(' mkdir websocketpp')
Logs.warn(' curl -L -O https://github.com/zaphoyd/websocketpp/archive/0.3.0-alpha4.tar.gz')
Logs.warn(' tar zxf 0.3.0-alpha4.tar.gz -C websocketpp/ --strip 1')
Logs.warn('Alternatively, Websocket support can be disabled with --without-websocket')
self.fatal("The configuration failed")
else:
self.end_msg(str(error))
+8
View File
@@ -112,6 +112,14 @@ FaceUri::FaceUri(const boost::asio::ip::udp::endpoint& endpoint)
m_port = boost::lexical_cast<std::string>(endpoint.port());
}
FaceUri::FaceUri(const boost::asio::ip::tcp::endpoint& endpoint, const std::string& scheme)
: m_scheme(scheme)
{
m_isV6 = endpoint.address().is_v6();
m_host = endpoint.address().to_string();
m_port = boost::lexical_cast<std::string>(endpoint.port());
}
#ifdef HAVE_UNIX_SOCKETS
FaceUri::FaceUri(const boost::asio::local::stream_protocol::endpoint& endpoint)
: m_isV6(false)
+3
View File
@@ -79,6 +79,9 @@ public: // scheme-specific construction
explicit
FaceUri(const boost::asio::ip::udp::endpoint& endpoint);
/// construct tcp canonical FaceUri with customized scheme
FaceUri(const boost::asio::ip::tcp::endpoint& endpoint, const std::string& scheme);
#ifdef HAVE_UNIX_SOCKETS
/// construct unix canonical FaceUri
explicit
+127
View File
@@ -0,0 +1,127 @@
/* -*- 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
*
* 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-channel.hpp"
#include "core/face-uri.hpp"
namespace nfd {
NFD_LOG_INIT("WebSocketChannel");
using namespace boost::asio;
WebSocketChannel::WebSocketChannel(const websocket::Endpoint& localEndpoint)
: m_localEndpoint(localEndpoint)
, m_isListening(false)
{
// Setup WebSocket server
m_server.clear_access_channels(websocketpp::log::alevel::all);
m_server.clear_error_channels(websocketpp::log::alevel::all);
m_server.set_message_handler(bind(&WebSocketChannel::handleMessage, this, _1, _2));
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());
this->setUri(FaceUri(localEndpoint, "ws"));
}
WebSocketChannel::~WebSocketChannel()
{
}
void
WebSocketChannel::handleMessage(websocketpp::connection_hdl hdl,
websocket::Server::message_ptr msg)
{
ChannelFaceMap::iterator it = m_channelFaces.find(hdl);
if (it != m_channelFaces.end())
{
it->second->handleReceive(msg->get_payload());
}
}
void
WebSocketChannel::handleOpen(websocketpp::connection_hdl hdl)
{
std::string remote;
try
{
remote = "wsclient://" + m_server.get_con_from_hdl(hdl)->get_remote_endpoint();
}
catch (websocketpp::lib::error_code ec)
{
NFD_LOG_DEBUG("handleOpen: cannot get remote uri");
websocketpp::lib::error_code ecode;
m_server.close(hdl, websocketpp::close::status::normal, "closed by channel", ecode);
}
shared_ptr<WebSocketFace> face = make_shared<WebSocketFace>(FaceUri(remote), this->getUri(),
hdl, boost::ref(m_server));
m_onFaceCreatedCallback(face);
m_channelFaces[hdl] = face;
}
void
WebSocketChannel::handleClose(websocketpp::connection_hdl hdl)
{
ChannelFaceMap::iterator it = m_channelFaces.find(hdl);
if (it != m_channelFaces.end())
{
NFD_LOG_DEBUG("handleClose: remove client");
m_channelFaces.erase(it);
}
}
void
WebSocketChannel::listen(const FaceCreatedCallback& onFaceCreated)
{
if (m_isListening)
{
throw Error("Listen already called on this channel");
}
m_isListening = true;
m_onFaceCreatedCallback = onFaceCreated;
try
{
m_server.listen(m_localEndpoint);
}
catch (websocketpp::lib::error_code ec)
{
throw Error("Failed to listen on local endpoint");
}
m_server.start_accept();
}
size_t
WebSocketChannel::size() const
{
return m_channelFaces.size();
}
} // namespace nfd
+122
View File
@@ -0,0 +1,122 @@
/* -*- 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
*
* 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_CHANNEL_HPP
#define NFD_DAEMON_FACE_WEBSOCKET_CHANNEL_HPP
#include "channel.hpp"
#include "core/global-io.hpp"
#include "core/scheduler.hpp"
#include "websocket-face.hpp"
namespace nfd {
/**
* \brief Class implementing WebSocket-based channel to create faces
*
*
*/
class WebSocketChannel : public Channel
{
public:
/**
* \brief Exception of WebSocketChannel
*/
class Error : public std::runtime_error
{
public:
explicit
Error(const std::string& what)
: runtime_error(what)
{
}
};
/**
* \brief Create WebSocket channel for the local endpoint
*
* 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
*/
explicit
WebSocketChannel(const websocket::Endpoint& localEndpoint);
virtual
~WebSocketChannel();
/**
* \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
*/
void
listen(const FaceCreatedCallback& onFaceCreated);
/**
* \brief Get number of faces in the channel
*/
size_t
size() const;
private:
void
handleMessage(websocketpp::connection_hdl hdl, websocket::Server::message_ptr msg);
void
handleOpen(websocketpp::connection_hdl hdl);
void
handleClose(websocketpp::connection_hdl hdl);
private:
websocket::Endpoint m_localEndpoint;
websocket::Server m_server;
/**
* Callbacks for face creation.
* New communications are detected using async_receive_from.
* Its handler has a fixed signature. No space for the face callback
*/
FaceCreatedCallback m_onFaceCreatedCallback;
typedef std::map< websocketpp::connection_hdl, shared_ptr<WebSocketFace> > ChannelFaceMap;
ChannelFaceMap m_channelFaces;
/**
* \brief If true, it means the function listen has already been called
*/
bool m_isListening;
};
} // namespace nfd
#endif // NFD_DAEMON_FACE_WEBSOCKET_CHANNEL_HPP
+97
View File
@@ -0,0 +1,97 @@
/* -*- 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
*
* 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)
{
}
void
WebSocketFace::sendInterest(const Interest& interest)
{
this->onSendInterest(interest);
const Block& payload = interest.wireEncode();
m_server.send(m_handle, payload.wire(), payload.size(), websocketpp::frame::opcode::binary);
}
void
WebSocketFace::sendData(const Data& data)
{
this->onSendData(data);
const Block& payload = data.wireEncode();
m_server.send(m_handle, payload.wire(), payload.size(), websocketpp::frame::opcode::binary);
}
void
WebSocketFace::close()
{
if (m_closed == false)
{
m_closed = true;
websocketpp::lib::error_code ecode;
m_server.close(m_handle, websocketpp::close::status::normal, "closed by nfd", ecode);
}
}
void
WebSocketFace::handleReceive(const std::string& msg)
{
// Copy message into Face internal buffer
BOOST_ASSERT(msg.size() <= MAX_NDN_PACKET_SIZE);
// Try to parse message data
bool isOk = true;
Block element;
isOk = Block::fromBuffer(reinterpret_cast<const uint8_t*>(msg.c_str()), msg.size(), element);
if (!isOk)
{
NFD_LOG_TRACE("[id:" << this->getId()
<< "] Received invalid NDN packet of length ["
<< msg.size() << "]");
return;
}
if (!this->decodeAndDispatchInput(element))
{
NFD_LOG_WARN("[id:" << this->getId()
<< "] Received unrecognized block of type ["
<< element.type() << "]");
// ignore unknown packet and proceed
}
}
} // namespace nfd
+77
View File
@@ -0,0 +1,77 @@
/* -*- 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
*
* 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/logger.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 boost::asio::ip::tcp::endpoint Endpoint;
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
virtual void
sendInterest(const Interest& interest);
virtual void
sendData(const Data& data);
virtual void
close();
void
handleReceive(const std::string& msg);
private:
websocketpp::connection_hdl m_handle;
websocket::Server& m_server;
bool m_closed;
};
} // namespace nfd
#endif // NFD_DAEMON_FACE_WEBSOCKET_FACE_HPP
+84
View File
@@ -0,0 +1,84 @@
/* -*- 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
*
* 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-factory.hpp"
namespace nfd {
using namespace boost::asio;
NFD_LOG_INIT("WebSocketFactory");
WebSocketFactory::WebSocketFactory(const std::string& defaultPort)
: m_defaultPort(defaultPort)
{
}
shared_ptr<WebSocketChannel>
WebSocketFactory::createChannel(const websocket::Endpoint& endpoint)
{
shared_ptr<WebSocketChannel> channel = findChannel(endpoint);
if (static_cast<bool>(channel))
return channel;
channel = make_shared<WebSocketChannel>(boost::cref(endpoint));
m_channels[endpoint] = channel;
return channel;
}
shared_ptr<WebSocketChannel>
WebSocketFactory::createChannel(const std::string& localIPAddress,
uint16_t localPort)
{
boost::system::error_code ec;
ip::address address = ip::address::from_string(localIPAddress, ec);
if (ec)
{
throw Error("Invalid address format: " + localIPAddress);
}
websocket::Endpoint endpoint(address, localPort);
return createChannel(endpoint);
}
shared_ptr<WebSocketChannel>
WebSocketFactory::findChannel(const websocket::Endpoint& localEndpoint)
{
ChannelMap::iterator i = m_channels.find(localEndpoint);
if (i != m_channels.end())
return i->second;
else
return shared_ptr<WebSocketChannel>();
}
void
WebSocketFactory::createFace(const FaceUri& uri,
const FaceCreatedCallback& onCreated,
const FaceConnectFailedCallback& onConnectFailed)
{
throw Error("WebSocketFactory does not support 'createFace' operation");
}
} // namespace nfd
+108
View File
@@ -0,0 +1,108 @@
/* -*- 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
*
* 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_FACTORY_HPP
#define NFD_DAEMON_FACE_WEBSOCKET_FACTORY_HPP
#include "protocol-factory.hpp"
#include "websocket-channel.hpp"
namespace nfd {
class WebSocketFactory : public ProtocolFactory
{
public:
/**
* \brief Exception of WebSocketFactory
*/
class Error : public ProtocolFactory::Error
{
public:
explicit
Error(const std::string& what)
: ProtocolFactory::Error(what)
{
}
};
explicit
WebSocketFactory(const std::string& defaultPort);
/**
* \brief Create WebSocket-based channel using websocket::Endpoint
*
* websocket::Endpoint is really an alias for boost::asio::ip::tcp::endpoint.
*
* If this method called twice with the same endpoint, only one channel
* will be created. The second call will just retrieve the existing
* channel.
*
* \returns always a valid pointer to a WebSocketChannel object, an exception
* is thrown if it cannot be created.
*
* \throws WebSocketFactory::Error
*
*/
shared_ptr<WebSocketChannel>
createChannel(const websocket::Endpoint& localEndpoint);
/**
* \brief Create WebSocket-based channel using specified ip address and port number
*
* \throws WebSocketFactory::Error
*/
shared_ptr<WebSocketChannel>
createChannel(const std::string& localIPAddress,
uint16_t localPort);
// from Factory
virtual void
createFace(const FaceUri& uri,
const FaceCreatedCallback& onCreated,
const FaceConnectFailedCallback& onConnectFailed);
private:
/**
* \brief Look up WebSocketChannel using specified local endpoint
*
* \returns shared pointer to the existing WebSocketChannel object
* or empty shared pointer when such channel does not exist
*
* \throws never
*/
shared_ptr<WebSocketChannel>
findChannel(const websocket::Endpoint& localEndpoint);
typedef std::map< websocket::Endpoint, shared_ptr<WebSocketChannel> > ChannelMap;
ChannelMap m_channels;
std::string m_defaultPort;
};
} // namespace nfd
#endif // NFD_DAEMON_FACE_WEBSOCKET_FACTORY_HPP
+36
View File
@@ -0,0 +1,36 @@
/* -*- 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
*
* 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_WEBSOCKETPP_HPP
#define NFD_DAEMON_FACE_WEBSOCKETPP_HPP
// suppress websocketpp warnings
#pragma GCC system_header
#pragma clang system_header
#include "websocketpp/config/asio_no_tls.hpp"
#include "websocketpp/server.hpp"
#endif // NFD_DAEMON_FACE_WEBSOCKETPP_HPP
+114
View File
@@ -41,6 +41,10 @@
#include "face/ethernet-factory.hpp"
#endif // HAVE_LIBPCAP
#ifdef HAVE_WEBSOCKET
#include "face/websocket-factory.hpp"
#endif // HAVE_WEBSOCKET
#include <ndn-cxx/management/nfd-face-event-notification.hpp>
namespace nfd {
@@ -142,6 +146,7 @@ FaceManager::onConfig(const ConfigSection& configSection,
bool hasSeenTcp = false;
bool hasSeenUdp = false;
bool hasSeenEther = false;
bool hasSeenWebSocket = false;
const std::list<shared_ptr<NetworkInterfaceInfo> > nicList(listNetworkInterfaces());
@@ -181,6 +186,14 @@ FaceManager::onConfig(const ConfigSection& configSection,
processSectionEther(item->second, isDryRun, nicList);
}
else if (item->first == "websocket")
{
if (hasSeenWebSocket)
throw Error("Duplicate \"websocket\" section");
hasSeenWebSocket = true;
processSectionWebSocket(item->second, isDryRun);
}
else
{
throw Error("Unrecognized option \"" + item->first + "\"");
@@ -621,6 +634,107 @@ FaceManager::processSectionEther(const ConfigSection& configSection,
#endif // HAVE_LIBPCAP
}
void
FaceManager::processSectionWebSocket(const ConfigSection& configSection, bool isDryRun)
{
// ; the websocket section contains settings of WebSocket faces and channels
// websocket
// {
// listen yes ; set to 'no' to disable WebSocket listener, default 'yes'
// port 9696 ; WebSocket listener port number
// enable_v4 yes ; set to 'no' to disable listening on IPv4 socket, default 'yes'
// enable_v6 yes ; set to 'no' to disable listening on IPv6 socket, default 'yes'
// }
#if defined(HAVE_WEBSOCKET)
std::string port = "9696";
bool needToListen = true;
bool enableV4 = true;
bool enableV6 = true;
for (ConfigSection::const_iterator i = configSection.begin();
i != configSection.end();
++i)
{
if (i->first == "port")
{
port = i->second.get_value<std::string>();
try
{
uint16_t portNo = boost::lexical_cast<uint16_t>(port);
NFD_LOG_TRACE("WebSocket port set to " << portNo);
}
catch (const std::bad_cast& error)
{
throw ConfigFile::Error("Invalid value for option " +
i->first + "\" in \"websocket\" section");
}
}
else if (i->first == "listen")
{
needToListen = parseYesNo(i, i->first, "websocket");
}
else if (i->first == "enable_v4")
{
enableV4 = parseYesNo(i, i->first, "websocket");
}
else if (i->first == "enable_v6")
{
enableV6 = parseYesNo(i, i->first, "websocket");
}
else
{
throw ConfigFile::Error("Unrecognized option \"" +
i->first + "\" in \"websocket\" section");
}
}
if (!enableV4 && !enableV6)
{
throw ConfigFile::Error("IPv4 and IPv6 channels have been disabled."
" Remove \"websocket\" section to disable WebSocket channels or"
" re-enable at least one channel type.");
}
if (!enableV4 && enableV6)
{
throw ConfigFile::Error("NFD does not allow pure IPv6 WebSocket channel.");
}
if (!isDryRun)
{
shared_ptr<WebSocketFactory> factory = make_shared<WebSocketFactory>(boost::cref(port));
m_factories.insert(std::make_pair("websocket", factory));
uint16_t portNo = boost::lexical_cast<uint16_t>(port);
if (enableV6 && enableV4)
{
shared_ptr<WebSocketChannel> ip46Channel = factory->createChannel("::", portNo);
if (needToListen)
{
ip46Channel->listen(bind(&FaceTable::add, &m_faceTable, _1));
}
m_factories.insert(std::make_pair("websocket46", factory));
}
else if (enableV4)
{
shared_ptr<WebSocketChannel> ipv4Channel = factory->createChannel("0.0.0.0", portNo);
if (needToListen)
{
ipv4Channel->listen(bind(&FaceTable::add, &m_faceTable, _1));
}
m_factories.insert(std::make_pair("websocket4", factory));
}
}
#else
throw ConfigFile::Error("NFD was compiled without WebSocket, "
"cannot process \"websocket\" section");
#endif // HAVE_WEBSOCKET
}
void
FaceManager::onFaceRequest(const Interest& request)
+3
View File
@@ -144,6 +144,9 @@ private:
bool isDryRun,
const std::list<shared_ptr<NetworkInterfaceInfo> >& nicList);
void
processSectionWebSocket(const ConfigSection& configSection, bool isDryRun);
/** \brief parse a config option that can be either "yes" or "no"
* \throw ConfigFile::Error value is neither "yes" nor "no"
* \return true if "yes", false if "no"
+10
View File
@@ -115,6 +115,16 @@ face_system
@IF_HAVE_LIBPCAP@ mcast yes ; set to 'no' to disable Ethernet multicast, default 'yes'
@IF_HAVE_LIBPCAP@ mcast_group 01:00:5E:00:17:AA ; Ethernet multicast group
@IF_HAVE_LIBPCAP@}
; The websocket section contains settings of WebSocket faces and channels.
@IF_HAVE_WEBSOCKET@websocket
@IF_HAVE_WEBSOCKET@{
@IF_HAVE_WEBSOCKET@ listen yes ; set to 'no' to disable WebSocket listener, default 'yes'
@IF_HAVE_WEBSOCKET@ port 9696 ; WebSocket listener port number
@IF_HAVE_WEBSOCKET@ enable_v4 yes ; set to 'no' to disable listening on IPv4 socket, default 'yes'
@IF_HAVE_WEBSOCKET@ enable_v6 yes ; set to 'no' to disable listening on IPv6 socket, default 'yes'
@IF_HAVE_WEBSOCKET@}
}
; The authorizations section grants privileges to authorized keys.
+5 -1
View File
@@ -52,7 +52,8 @@ def build(bld):
features='cxx cxxprogram',
source=bld.path.ant_glob(['daemon/**/*.cpp'],
excl=['daemon/face/ethernet.cpp',
'daemon/face/unix-*.cpp']),
'daemon/face/unix-*.cpp',
'daemon/face/websocket-*.cpp']),
use='daemon-objects unit-tests-main',
includes='.',
install_path=None,
@@ -64,6 +65,9 @@ def build(bld):
if bld.env['HAVE_UNIX_SOCKETS']:
unit_tests_nfd.source += bld.path.ant_glob('daemon/face/unix-*.cpp')
if bld.env['HAVE_WEBSOCKET']:
unit_tests_nfd.source += bld.path.ant_glob('daemon/face/websocket-*.cpp')
unit_tests_rib = bld.program(
target='../unit-tests-rib',
features='cxx cxxprogram',
Submodule
+1
Submodule websocketpp added at e7ce038207
+11 -4
View File
@@ -32,13 +32,14 @@ from waflib import Logs, Utils, Context
def options(opt):
opt.load(['compiler_cxx', 'gnu_dirs'])
opt.load(['boost', 'unix-socket', 'dependency-checker',
opt.load(['boost', 'unix-socket', 'dependency-checker', 'websocket',
'default-compiler-flags', 'coverage',
'doxygen', 'sphinx_build'],
tooldir=['.waf-tools'])
nfdopt = opt.add_option_group('NFD Options')
opt.addUnixOptions(nfdopt)
opt.addWebsocketOptions(nfdopt)
opt.addDependencyOptions(nfdopt, 'libpcap')
nfdopt.add_option('--without-libpcap', action='store_true', default=False,
dest='without_libpcap',
@@ -55,7 +56,7 @@ def options(opt):
def configure(conf):
conf.load(['compiler_cxx', 'gnu_dirs',
'default-compiler-flags',
'boost', 'dependency-checker',
'boost', 'dependency-checker', 'websocket',
'doxygen', 'sphinx_build'])
conf.check_cfg(package='libndn-cxx', args=['--cflags', '--libs'],
@@ -79,6 +80,7 @@ def configure(conf):
return
conf.load('unix-socket')
conf.checkWebsocket(mandatory=True)
conf.checkDependency(name='librt', lib='rt', mandatory=False)
conf.checkDependency(name='libresolv', lib='resolv', mandatory=False)
@@ -130,9 +132,10 @@ def build(bld):
source=bld.path.ant_glob(['daemon/**/*.cpp'],
excl=['daemon/face/ethernet-*.cpp',
'daemon/face/unix-*.cpp',
'daemon/face/websocket-*.cpp',
'daemon/main.cpp']),
use='core-objects',
includes='daemon',
includes='daemon websocketpp',
export_includes='daemon',
)
@@ -143,6 +146,9 @@ def build(bld):
if bld.env['HAVE_UNIX_SOCKETS']:
nfd_objects.source += bld.path.ant_glob('daemon/face/unix-*.cpp')
if bld.env['HAVE_WEBSOCKET']:
nfd_objects.source += bld.path.ant_glob('daemon/face/websocket-*.cpp')
bld(target='bin/nfd',
features='cxx cxxprogram',
source='daemon/main.cpp',
@@ -177,7 +183,8 @@ def build(bld):
source='nfd.conf.sample.in',
target='nfd.conf.sample',
install_path="${SYSCONFDIR}/ndn",
IF_HAVE_LIBPCAP="" if bld.env['HAVE_LIBPCAP'] else "; ")
IF_HAVE_LIBPCAP="" if bld.env['HAVE_LIBPCAP'] else "; ",
IF_HAVE_WEBSOCKET="" if bld.env['HAVE_WEBSOCKET'] else "; ")
bld(features='subst',
source='tools/nfd-status-http-server.py',