face: Implementation of encode/decode of LocalControlHeader
LocalControlHeader can only be used on faces that are derived from
LocalFace. UnixStreamFace is directly inherited from LocalFace,
TCP face has two specializations: generic TcpFace (strictly not local),
and LocalTcpFace.
refs #1213
Change-Id: I8a158c3bc4bb929eedd15757cfddecc0d1049f9f
diff --git a/daemon/common.hpp b/daemon/common.hpp
index 76bbab5..af4a9fd 100644
--- a/daemon/common.hpp
+++ b/daemon/common.hpp
@@ -49,6 +49,7 @@
using boost::enable_shared_from_this;
using boost::make_shared;
using boost::static_pointer_cast;
+using boost::dynamic_pointer_cast;
using boost::function;
using boost::bind;
diff --git a/daemon/core/logger.hpp b/daemon/core/logger.hpp
index 6732384..f8c6e8e 100644
--- a/daemon/core/logger.hpp
+++ b/daemon/core/logger.hpp
@@ -68,6 +68,10 @@
template<> \
nfd::Logger cls<specialization>::g_logger = nfd::Logger(name);
+#define NFD_LOG_INCLASS_2TEMPLATE_SPECIALIZATION_DEFINE(cls, s1, s2, name) \
+ template<> \
+ nfd::Logger cls<s1, s2>::g_logger = nfd::Logger(name);
+
#define NFD_LOG_TRACE(expression) \
if(g_logger.isEnabled(nfd::LOG_TRACE)) \
std::cerr<<"TRACE: "<<"["<<g_logger<<"] " << expression << "\n"
diff --git a/daemon/face/face.cpp b/daemon/face/face.cpp
index 5ca8f29..cc4fba8 100644
--- a/daemon/face/face.cpp
+++ b/daemon/face/face.cpp
@@ -13,7 +13,6 @@
Face::Face()
: m_id(INVALID_FACEID)
- , m_localControlHeaderFeatures(LOCAL_CONTROL_HEADER_FEATURE_MAX)
{
}
@@ -35,6 +34,20 @@
}
bool
+Face::isLocal() const
+{
+ return m_isLocal;
+}
+
+// this method is protected and can be used only in derived class
+// to set localhost scope
+void
+Face::setLocal(bool isLocal)
+{
+ m_isLocal = isLocal;
+}
+
+bool
Face::isUp() const
{
return true;
@@ -58,21 +71,27 @@
return false;
}
-void
-Face::setLocalControlHeaderFeature(LocalControlHeaderFeature feature, bool enabled)
+bool
+Face::decodeAndDispatchInput(const Block& element)
{
- BOOST_ASSERT(feature > LOCAL_CONTROL_HEADER_FEATURE_ANY &&
- feature < m_localControlHeaderFeatures.size());
- m_localControlHeaderFeatures[feature] = enabled;
- NFD_LOG_DEBUG("face" << this->getId() << " setLocalControlHeaderFeature " <<
- (enabled ? "enable" : "disable") << " feature " << feature);
-
- BOOST_STATIC_ASSERT(LOCAL_CONTROL_HEADER_FEATURE_ANY == 0);
- m_localControlHeaderFeatures[LOCAL_CONTROL_HEADER_FEATURE_ANY] =
- std::find(m_localControlHeaderFeatures.begin() + 1,
- m_localControlHeaderFeatures.end(), true) <
- m_localControlHeaderFeatures.end();
- // 'find(..) < .end()' instead of 'find(..) != .end()' due to LLVM Bug 16816
+ /// \todo Ensure lazy field decoding process
+
+ if (element.type() == tlv::Interest)
+ {
+ shared_ptr<Interest> i = make_shared<Interest>();
+ i->wireDecode(element);
+ this->onReceiveInterest(*i);
+ }
+ else if (element.type() == tlv::Data)
+ {
+ shared_ptr<Data> d = make_shared<Data>();
+ d->wireDecode(element);
+ this->onReceiveData(*d);
+ }
+ else
+ return false;
+
+ return true;
}
} //namespace nfd
diff --git a/daemon/face/face.hpp b/daemon/face/face.hpp
index 924b4fa..f3c5d40 100644
--- a/daemon/face/face.hpp
+++ b/daemon/face/face.hpp
@@ -22,21 +22,6 @@
const std::size_t MAX_NDN_PACKET_SIZE = 8800;
-/* \brief indicates a feature in LocalControlHeader
- */
-enum LocalControlHeaderFeature
-{
- /// any feature
- LOCAL_CONTROL_HEADER_FEATURE_ANY,
- /// in-faceid
- LOCAL_CONTROL_HEADER_FEATURE_IN_FACEID,
- /// out-faceid
- LOCAL_CONTROL_HEADER_FEATURE_NEXTHOP_FACEID,
- /// upper bound of enum
- LOCAL_CONTROL_HEADER_FEATURE_MAX
-};
-
-
/** \brief represents a face
*/
class Face : noncopyable, public enable_shared_from_this<Face>
@@ -75,22 +60,14 @@
virtual void
sendData(const Data& data) = 0;
- /**
- * \brief Close the face
+ /** \brief Close the face
*
- * This terminates all communication on the face and cause
- * onFail() method event to be invoked
+ * This terminates all communication on the face and cause
+ * onFail() method event to be invoked
*/
virtual void
close() = 0;
- /** \brief Get whether face is connected to a local app
- *
- * In this base class this property is always false.
- */
- virtual bool
- isLocal() const = 0;
-
/** \brief Get whether underlying communication is up
*
* In this base class this property is always true.
@@ -98,6 +75,14 @@
virtual bool
isUp() const;
+ /** \brief Get whether face is connected to a local app
+ *
+ * False by default and can become true if a derived class, implementing
+ * one of the local face types, explicitly calls Face::setLocal(true)
+ */
+ bool
+ isLocal() const;
+
/** \brief Set the description
*
* This is typically invoked by mgmt on set description command
@@ -116,22 +101,13 @@
virtual bool
isMultiAccess() const;
- /** \brief get whether a LocalControlHeader feature is enabled
- *
- * \param feature The feature. Cannot be LOCAL_CONTROL_HEADER_FEATURE_MAX
- * LOCAL_CONTROL_HEADER_FEATURE_ANY returns true if any feature is enabled.
- */
- bool
- isLocalControlHeaderEnabled(LocalControlHeaderFeature feature =
- LOCAL_CONTROL_HEADER_FEATURE_ANY) const;
-
- /** \brief enable or disable a LocalControlHeader feature
- *
- * \param feature The feature. Cannot be LOCAL_CONTROL_HEADER_FEATURE_ANY
- * or LOCAL_CONTROL_HEADER_FEATURE_MAX
- */
+protected:
void
- setLocalControlHeaderFeature(LocalControlHeaderFeature feature, bool enabled);
+ setLocal(bool isLocal);
+
+ // this is a non-virtual method
+ bool
+ decodeAndDispatchInput(const Block& element);
private:
void
@@ -140,19 +116,12 @@
private:
FaceId m_id;
std::string m_description;
- std::vector<bool> m_localControlHeaderFeatures;
-
+ bool m_isLocal; // for scoping purposes
+
// allow setting FaceId
friend class Forwarder;
};
-inline bool
-Face::isLocalControlHeaderEnabled(LocalControlHeaderFeature feature) const
-{
- BOOST_ASSERT(feature < m_localControlHeaderFeatures.size());
- return m_localControlHeaderFeatures[feature];
-}
-
} // namespace nfd
#endif // NFD_FACE_FACE_HPP
diff --git a/daemon/face/local-face.hpp b/daemon/face/local-face.hpp
new file mode 100644
index 0000000..6175b5d
--- /dev/null
+++ b/daemon/face/local-face.hpp
@@ -0,0 +1,179 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NFD_FACE_LOCAL_FACE_HPP
+#define NFD_FACE_LOCAL_FACE_HPP
+
+#include "face.hpp"
+
+namespace nfd {
+
+/* \brief indicates a feature in LocalControlHeader
+ */
+enum LocalControlHeaderFeature
+{
+ /// any feature
+ LOCAL_CONTROL_HEADER_FEATURE_ANY,
+ /// in-faceid
+ LOCAL_CONTROL_HEADER_FEATURE_IN_FACEID,
+ /// out-faceid
+ LOCAL_CONTROL_HEADER_FEATURE_NEXTHOP_FACEID,
+ /// upper bound of enum
+ LOCAL_CONTROL_HEADER_FEATURE_MAX
+};
+
+
+/** \brief represents a face
+ */
+class LocalFace : public Face
+{
+public:
+ LocalFace();
+
+ /** \brief get whether a LocalControlHeader feature is enabled
+ *
+ * \param feature The feature. Cannot be LOCAL_CONTROL_HEADER_FEATURE_MAX
+ * LOCAL_CONTROL_HEADER_FEATURE_ANY returns true if any feature is enabled.
+ */
+ bool
+ isLocalControlHeaderEnabled(LocalControlHeaderFeature feature =
+ LOCAL_CONTROL_HEADER_FEATURE_ANY) const;
+
+ /** \brief enable or disable a LocalControlHeader feature
+ *
+ * \param feature The feature. Cannot be LOCAL_CONTROL_HEADER_FEATURE_ANY
+ * or LOCAL_CONTROL_HEADER_FEATURE_MAX
+ */
+ void
+ setLocalControlHeaderFeature(LocalControlHeaderFeature feature, bool enabled = true);
+
+protected:
+ // statically overridden from Face
+
+ /** \brief Decode block into Interest/Data, considering potential LocalControlHeader
+ *
+ * If LocalControlHeader is present, the encoded data is filtered out, based
+ * on enabled features on the face.
+ */
+ bool
+ decodeAndDispatchInput(const Block& element);
+
+ // LocalFace-specific methods
+
+ /** \brief Check if LocalControlHeader needs to be included, taking into account
+ * both set parameters in supplied LocalControlHeader and features
+ * enabled on the local face.
+ */
+ bool
+ isEmptyFilteredLocalControlHeader(const ndn::nfd::LocalControlHeader& header) const;
+
+ /** \brief Create LocalControlHeader, considering enabled features
+ */
+ template<class Packet>
+ Block
+ filterAndEncodeLocalControlHeader(const Packet& packet);
+
+private:
+ std::vector<bool> m_localControlHeaderFeatures;
+};
+
+inline
+LocalFace::LocalFace()
+ : m_localControlHeaderFeatures(LOCAL_CONTROL_HEADER_FEATURE_MAX)
+{
+ setLocal(true);
+}
+
+inline bool
+LocalFace::isLocalControlHeaderEnabled(LocalControlHeaderFeature feature) const
+{
+ BOOST_ASSERT(feature < m_localControlHeaderFeatures.size());
+ return m_localControlHeaderFeatures[feature];
+}
+
+inline void
+LocalFace::setLocalControlHeaderFeature(LocalControlHeaderFeature feature, bool enabled/* = true*/)
+{
+ BOOST_ASSERT(feature > LOCAL_CONTROL_HEADER_FEATURE_ANY &&
+ feature < m_localControlHeaderFeatures.size());
+ m_localControlHeaderFeatures[feature] = enabled;
+
+ BOOST_STATIC_ASSERT(LOCAL_CONTROL_HEADER_FEATURE_ANY == 0);
+ m_localControlHeaderFeatures[LOCAL_CONTROL_HEADER_FEATURE_ANY] =
+ std::find(m_localControlHeaderFeatures.begin() + 1,
+ m_localControlHeaderFeatures.end(), true) <
+ m_localControlHeaderFeatures.end();
+ // 'find(..) < .end()' instead of 'find(..) != .end()' due to LLVM Bug 16816
+}
+
+inline bool
+LocalFace::decodeAndDispatchInput(const Block& element)
+{
+ const Block& payload = ndn::nfd::LocalControlHeader::getPayload(element);
+
+ // If received LocalControlHeader, but it is not enabled on the face
+ if ((&payload != &element) && !this->isLocalControlHeaderEnabled())
+ return false;
+
+ if (payload.type() == tlv::Interest)
+ {
+ shared_ptr<Interest> i = make_shared<Interest>();
+ i->wireDecode(payload);
+ if (&payload != &element)
+ {
+ i->getLocalControlHeader().wireDecode(element,
+ false,
+ this->isLocalControlHeaderEnabled(LOCAL_CONTROL_HEADER_FEATURE_NEXTHOP_FACEID));
+ }
+
+ this->onReceiveInterest(*i);
+ }
+ else if (payload.type() == tlv::Data)
+ {
+ shared_ptr<Data> d = make_shared<Data>();
+ d->wireDecode(payload);
+
+ /// \todo Uncomment and correct the following when we have more
+ /// options in LocalControlHeader that apply for incoming
+ /// Data packets (if ever)
+ // if (&payload != &element)
+ // {
+ //
+ // d->getLocalControlHeader().wireDecode(element,
+ // false,
+ // false);
+ // }
+
+ this->onReceiveData(*d);
+ }
+ else
+ return false;
+
+ return true;
+}
+
+inline bool
+LocalFace::isEmptyFilteredLocalControlHeader(const ndn::nfd::LocalControlHeader& header) const
+{
+ if (!this->isLocalControlHeaderEnabled())
+ return true;
+
+ return header.empty(this->isLocalControlHeaderEnabled(LOCAL_CONTROL_HEADER_FEATURE_IN_FACEID),
+ false);
+}
+
+template<class Packet>
+inline Block
+LocalFace::filterAndEncodeLocalControlHeader(const Packet& packet)
+{
+ return packet.getLocalControlHeader().wireEncode(packet,
+ this->isLocalControlHeaderEnabled(LOCAL_CONTROL_HEADER_FEATURE_IN_FACEID),
+ false);
+}
+
+} // namespace nfd
+
+#endif // NFD_FACE_LOCAL_FACE_HPP
diff --git a/daemon/face/stream-face.hpp b/daemon/face/stream-face.hpp
index ac08421..9baef1d 100644
--- a/daemon/face/stream-face.hpp
+++ b/daemon/face/stream-face.hpp
@@ -8,14 +8,18 @@
#define NFD_FACE_STREAM_FACE_HPP
#include "face.hpp"
+#include "local-face.hpp"
namespace nfd {
-template <class T>
-class StreamFace : public Face
+// forward declaration
+template<class T, class U, class V> struct StreamFaceSenderImpl;
+
+template<class Protocol, class FaceBase = Face>
+class StreamFace : public FaceBase
{
public:
- typedef T protocol;
+ typedef Protocol protocol;
/**
* \brief Create instance of StreamFace
@@ -37,6 +41,12 @@
protected:
void
+ processErrorCode(const boost::system::error_code& error);
+
+ void
+ handleSend(const boost::system::error_code& error,
+ const Block& header, const Block& payload);
+ void
handleSend(const boost::system::error_code& error,
const Block& wire);
@@ -56,159 +66,201 @@
private:
uint8_t m_inputBuffer[MAX_NDN_PACKET_SIZE];
std::size_t m_inputBufferSize;
-
+
+ friend struct StreamFaceSenderImpl<Protocol, FaceBase, Interest>;
+ friend struct StreamFaceSenderImpl<Protocol, FaceBase, Data>;
+
NFD_LOG_INCLASS_DECLARE();
};
// All inherited classes must use
// NFD_LOG_INCLASS_TEMPLATE_SPECIALIZATION_DEFINE(StreamFace, <specialization-parameter>, "Name");
-template <class T>
+
+/** \brief Class allowing validation of the StreamFace use
+ *
+ * For example, partial specialization based on boost::asio::ip::tcp should check
+ * that local endpoint is loopback
+ *
+ * @throws Face::Error if validation failed
+ */
+template<class Protocol, class U>
+struct StreamFaceValidator
+{
+ static void
+ validateSocket(typename Protocol::socket& socket)
+ {
+ }
+};
+
+
+template<class T, class U>
inline
-StreamFace<T>::StreamFace(const shared_ptr<typename StreamFace::protocol::socket>& socket)
+StreamFace<T, U>::StreamFace(const shared_ptr<typename StreamFace::protocol::socket>& socket)
: m_socket(socket)
, m_inputBufferSize(0)
{
+ StreamFaceValidator<T, U>::validateSocket(*socket);
m_socket->async_receive(boost::asio::buffer(m_inputBuffer, MAX_NDN_PACKET_SIZE), 0,
- bind(&StreamFace<T>::handleReceive, this, _1, _2));
+ bind(&StreamFace<T, U>::handleReceive, this, _1, _2));
}
-template <class T>
+template<class T, class U>
inline
-StreamFace<T>::~StreamFace()
+StreamFace<T, U>::~StreamFace()
{
}
-
-template <class T>
-inline void
-StreamFace<T>::sendInterest(const Interest& interest)
+template<class Protocol, class FaceBase, class Packet>
+struct StreamFaceSenderImpl
{
- m_socket->async_send(boost::asio::buffer(interest.wireEncode().wire(),
- interest.wireEncode().size()),
- bind(&StreamFace<T>::handleSend, this, _1, interest.wireEncode()));
-
- // anything else should be done here?
+ static void
+ send(StreamFace<Protocol, FaceBase>& face, const Packet& packet)
+ {
+ face.m_socket->async_send(boost::asio::buffer(packet.wireEncode().wire(),
+ packet.wireEncode().size()),
+ bind(&StreamFace<Protocol, FaceBase>::handleSend,
+ &face, _1, packet.wireEncode()));
+ }
+};
+
+// partial specialization (only classes can be partially specialized)
+template<class Protocol, class Packet>
+struct StreamFaceSenderImpl<Protocol, LocalFace, Packet>
+{
+ static void
+ send(StreamFace<Protocol, LocalFace>& face, const Packet& packet)
+ {
+ using namespace boost::asio;
+
+ if (face.isEmptyFilteredLocalControlHeader(packet.getLocalControlHeader()))
+ {
+ const Block& payload = packet.wireEncode();
+ face.m_socket->async_send(buffer(payload.wire(), payload.size()),
+ bind(&StreamFace<Protocol, LocalFace>::handleSend,
+ &face, _1, packet.wireEncode()));
+ }
+ else
+ {
+ Block header = face.filterAndEncodeLocalControlHeader(packet);
+ const Block& payload = packet.wireEncode();
+
+ std::vector<const_buffer> buffers;
+ buffers.reserve(2);
+ buffers.push_back(buffer(header.wire(), header.size()));
+ buffers.push_back(buffer(payload.wire(), payload.size()));
+
+ face.m_socket->async_send(buffers,
+ bind(&StreamFace<Protocol, LocalFace>::handleSend,
+ &face, _1, header, payload));
+ }
+ }
+};
+
+
+template<class T, class U>
+inline void
+StreamFace<T, U>::sendInterest(const Interest& interest)
+{
+ StreamFaceSenderImpl<T, U, Interest>::send(*this, interest);
}
-template <class T>
+template<class T, class U>
inline void
-StreamFace<T>::sendData(const Data& data)
+StreamFace<T, U>::sendData(const Data& data)
{
- m_socket->async_send(boost::asio::buffer(data.wireEncode().wire(),
- data.wireEncode().size()),
- bind(&StreamFace<T>::handleSend, this, _1, data.wireEncode()));
-
- // anything else should be done here?
+ StreamFaceSenderImpl<T, U, Data>::send(*this, data);
}
-template <class T>
+template<class T, class U>
inline void
-StreamFace<T>::close()
+StreamFace<T, U>::close()
{
if (!m_socket->is_open())
return;
-
+
NFD_LOG_INFO("[id:" << this->getId()
<< ",endpoint:" << m_socket->local_endpoint()
<< "] Close connection");
closeSocket();
- onFail("Close connection");
+ this->onFail("Close connection");
}
-template <class T>
+template<class T, class U>
inline void
-StreamFace<T>::handleSend(const boost::system::error_code& error,
- const Block& wire)
+StreamFace<T, U>::processErrorCode(const boost::system::error_code& error)
{
- if (error) {
- if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
- return;
-
- if (!m_socket->is_open())
- {
- onFail("Connection closed");
- return;
- }
-
- if (error == boost::asio::error::eof)
- {
- NFD_LOG_INFO("[id:" << this->getId()
- << ",endpoint:" << m_socket->local_endpoint()
- << "] Connection closed");
- }
- else
- {
- NFD_LOG_WARN("[id:" << this->getId()
- << ",endpoint:" << m_socket->local_endpoint()
- << "] Send operation failed, closing socket: "
- << error.category().message(error.value()));
- }
-
- closeSocket();
-
- if (error == boost::asio::error::eof)
- {
- onFail("Connection closed");
- }
- else
- {
- onFail("Send operation failed, closing socket: " +
- error.category().message(error.value()));
- }
+ if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
return;
- }
+
+ if (!m_socket->is_open())
+ {
+ this->onFail("Connection closed");
+ return;
+ }
+
+ if (error == boost::asio::error::eof)
+ {
+ NFD_LOG_INFO("[id:" << this->getId()
+ << ",endpoint:" << m_socket->local_endpoint()
+ << "] Connection closed");
+ }
+ else
+ {
+ NFD_LOG_WARN("[id:" << this->getId()
+ << ",endpoint:" << m_socket->local_endpoint()
+ << "] Send or receive operation failed, closing socket: "
+ << error.category().message(error.value()));
+ }
+
+ closeSocket();
+
+ if (error == boost::asio::error::eof)
+ {
+ this->onFail("Connection closed");
+ }
+ else
+ {
+ this->onFail("Send or receive operation failed, closing socket: " +
+ error.category().message(error.value()));
+ }
+}
+
+
+template<class T, class U>
+inline void
+StreamFace<T, U>::handleSend(const boost::system::error_code& error,
+ const Block& wire)
+{
+ if (error)
+ return processErrorCode(error);
NFD_LOG_TRACE("[id:" << this->getId()
<< ",endpoint:" << m_socket->local_endpoint()
<< "] Successfully sent: " << wire.size() << " bytes");
- // do nothing (needed to retain validity of wire memory block
}
-template <class T>
+template<class T, class U>
inline void
-StreamFace<T>::handleReceive(const boost::system::error_code& error,
+StreamFace<T, U>::handleSend(const boost::system::error_code& error,
+ const Block& header, const Block& payload)
+{
+ if (error)
+ return processErrorCode(error);
+
+ NFD_LOG_TRACE("[id:" << this->getId()
+ << ",endpoint:" << m_socket->local_endpoint()
+ << "] Successfully sent: " << (header.size()+payload.size()) << " bytes");
+}
+
+template<class T, class U>
+inline void
+StreamFace<T, U>::handleReceive(const boost::system::error_code& error,
std::size_t bytes_recvd)
{
- if (error || bytes_recvd == 0) {
- if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
- return;
-
- // this should be unnecessary, but just in case
- if (!m_socket->is_open())
- {
- onFail("Connection closed");
- return;
- }
-
- if (error == boost::asio::error::eof)
- {
- NFD_LOG_INFO("[id:" << this->getId()
- << ",endpoint:" << m_socket->local_endpoint()
- << "] Connection closed");
- }
- else
- {
- NFD_LOG_WARN("[id:" << this->getId()
- << ",endpoint:" << m_socket->local_endpoint()
- << "] Receive operation failed: "
- << error.category().message(error.value()));
- }
-
- closeSocket();
-
- if (error == boost::asio::error::eof)
- {
- onFail("Connection closed");
- }
- else
- {
- onFail("Receive operation failed, closing socket: " +
- error.category().message(error.value()));
- }
- return;
- }
+ if (error)
+ return processErrorCode(error);
NFD_LOG_TRACE("[id:" << this->getId()
<< ",endpoint:" << m_socket->local_endpoint()
@@ -226,27 +278,8 @@
offset += element.size();
BOOST_ASSERT(offset <= m_inputBufferSize);
-
- /// @todo Ensure lazy field decoding process
- if (element.type() == tlv::Interest)
- {
- shared_ptr<Interest> i = make_shared<Interest>();
- i->wireDecode(element);
- onReceiveInterest(*i);
- }
- else if (element.type() == tlv::Data)
- {
- shared_ptr<Data> d = make_shared<Data>();
- d->wireDecode(element);
- onReceiveData(*d);
- }
- // @todo Add local header support
- // else if (element.type() == tlv::LocalHeader)
- // {
- // shared_ptr<Interest> i = make_shared<Interest>();
- // i->wireDecode(element);
- // }
- else
+
+ if (!this->decodeAndDispatchInput(element))
{
NFD_LOG_WARN("[id:" << this->getId()
<< ",endpoint:" << m_socket->local_endpoint()
@@ -265,7 +298,7 @@
<< "closing down the face");
closeSocket();
- onFail("Received input is invalid or too large to process, closing down the face");
+ this->onFail("Received input is invalid or too large to process, closing down the face");
return;
}
}
@@ -286,18 +319,18 @@
m_socket->async_receive(boost::asio::buffer(m_inputBuffer + m_inputBufferSize,
MAX_NDN_PACKET_SIZE - m_inputBufferSize), 0,
- bind(&StreamFace<T>::handleReceive, this, _1, _2));
+ bind(&StreamFace<T, U>::handleReceive, this, _1, _2));
}
-template <class T>
+template<class T, class U>
inline void
-StreamFace<T>::keepFaceAliveUntilAllHandlersExecuted(const shared_ptr<Face>& face)
+StreamFace<T, U>::keepFaceAliveUntilAllHandlersExecuted(const shared_ptr<Face>& face)
{
}
-template <class T>
+template<class T, class U>
inline void
-StreamFace<T>::closeSocket()
+StreamFace<T, U>::closeSocket()
{
boost::asio::io_service& io = m_socket->get_io_service();
@@ -309,7 +342,7 @@
// ensure that the Face object is alive at least until all pending
// handlers are dispatched
- io.post(bind(&StreamFace<T>::keepFaceAliveUntilAllHandlersExecuted,
+ io.post(bind(&StreamFace<T, U>::keepFaceAliveUntilAllHandlersExecuted,
this, this->shared_from_this()));
}
diff --git a/daemon/face/tcp-channel.cpp b/daemon/face/tcp-channel.cpp
index 087a24c..34b734a 100644
--- a/daemon/face/tcp-channel.cpp
+++ b/daemon/face/tcp-channel.cpp
@@ -123,7 +123,12 @@
{
tcp::Endpoint remoteEndpoint = socket->remote_endpoint();
- shared_ptr<TcpFace> face = make_shared<TcpFace>(boost::cref(socket));
+ shared_ptr<Face> face;
+ if (socket->local_endpoint().address().is_loopback())
+ face = make_shared<TcpLocalFace>(boost::cref(socket));
+ else
+ face = make_shared<TcpFace>(boost::cref(socket));
+
face->onFail += bind(&TcpChannel::afterFaceFailed, this, remoteEndpoint);
onFaceCreated(face);
diff --git a/daemon/face/tcp-channel.hpp b/daemon/face/tcp-channel.hpp
index 4cca5c5..db6521f 100644
--- a/daemon/face/tcp-channel.hpp
+++ b/daemon/face/tcp-channel.hpp
@@ -32,7 +32,7 @@
* (as a response to incoming connection or after connection
* is established)
*/
- typedef function<void(const shared_ptr<TcpFace>& newFace)> FaceCreatedCallback;
+ typedef function<void(const shared_ptr<Face>& newFace)> FaceCreatedCallback;
/**
* \brief Prototype for the callback that is called when face is failed to
@@ -135,7 +135,7 @@
boost::asio::io_service& m_ioService;
tcp::Endpoint m_localEndpoint;
- typedef std::map< tcp::Endpoint, shared_ptr<TcpFace> > ChannelFaceMap;
+ typedef std::map< tcp::Endpoint, shared_ptr<Face> > ChannelFaceMap;
ChannelFaceMap m_channelFaces;
bool isListening;
diff --git a/daemon/face/tcp-face.cpp b/daemon/face/tcp-face.cpp
index 874de98..4f8cbab 100644
--- a/daemon/face/tcp-face.cpp
+++ b/daemon/face/tcp-face.cpp
@@ -13,15 +13,19 @@
NFD_LOG_INCLASS_TEMPLATE_SPECIALIZATION_DEFINE(StreamFace, TcpFace::protocol, "TcpFace");
+NFD_LOG_INCLASS_2TEMPLATE_SPECIALIZATION_DEFINE(StreamFace,
+ TcpLocalFace::protocol, LocalFace, "TcpLocalFace");
+
TcpFace::TcpFace(const shared_ptr<TcpFace::protocol::socket>& socket)
: StreamFace<protocol>(socket)
{
}
-bool
-TcpFace::isLocal() const
+//
+
+TcpLocalFace::TcpLocalFace(const shared_ptr<TcpLocalFace::protocol::socket>& socket)
+ : StreamFace<protocol, LocalFace>(socket)
{
- return false;
}
diff --git a/daemon/face/tcp-face.hpp b/daemon/face/tcp-face.hpp
index c41f601..dfd6028 100644
--- a/daemon/face/tcp-face.hpp
+++ b/daemon/face/tcp-face.hpp
@@ -23,11 +23,45 @@
explicit
TcpFace(const shared_ptr<protocol::socket>& socket);
-
- virtual bool
- isLocal() const;
};
+//
+
+/** \brief Class validating use of TcpLocalFace
+ */
+template<>
+struct StreamFaceValidator<boost::asio::ip::tcp, LocalFace>
+{
+ /** Check that local endpoint is loopback
+ *
+ * @throws Face::Error if validation failed
+ */
+ static void
+ validateSocket(boost::asio::ip::tcp::socket& socket)
+ {
+ if (!socket.local_endpoint().address().is_loopback() ||
+ !socket.remote_endpoint().address().is_loopback())
+ {
+ throw Face::Error("TcpLocalFace can be created only on loopback interface");
+ }
+ }
+};
+
+/**
+ * \brief Implementation of Face abstraction that uses TCP
+ * as underlying transport mechanism and is used for
+ * local communication (can enable LocalControlHeader)
+ */
+class TcpLocalFace : public StreamFace<boost::asio::ip::tcp, LocalFace>
+{
+public:
+ typedef boost::asio::ip::tcp protocol;
+
+ explicit
+ TcpLocalFace(const shared_ptr<protocol::socket>& socket);
+};
+
+
} // namespace nfd
#endif // NFD_FACE_TCP_FACE_HPP
diff --git a/daemon/face/unix-stream-face.cpp b/daemon/face/unix-stream-face.cpp
index de7c4f9..27ba693 100644
--- a/daemon/face/unix-stream-face.cpp
+++ b/daemon/face/unix-stream-face.cpp
@@ -11,17 +11,13 @@
// The whole purpose of this file is to specialize the logger,
// otherwise, everything could be put into the header file.
-NFD_LOG_INCLASS_TEMPLATE_SPECIALIZATION_DEFINE(StreamFace, UnixStreamFace::protocol, "UnixStreamFace");
+NFD_LOG_INCLASS_2TEMPLATE_SPECIALIZATION_DEFINE(StreamFace,
+ UnixStreamFace::protocol, LocalFace,
+ "UnixStreamFace");
UnixStreamFace::UnixStreamFace(const shared_ptr<UnixStreamFace::protocol::socket>& socket)
- : StreamFace<protocol>(socket)
+ : StreamFace<protocol, LocalFace>(socket)
{
}
-bool
-UnixStreamFace::isLocal() const
-{
- return true;
-}
-
} // namespace nfd
diff --git a/daemon/face/unix-stream-face.hpp b/daemon/face/unix-stream-face.hpp
index cc97c21..8492f54 100644
--- a/daemon/face/unix-stream-face.hpp
+++ b/daemon/face/unix-stream-face.hpp
@@ -20,20 +20,13 @@
* \brief Implementation of Face abstraction that uses stream-oriented
* Unix domain sockets as underlying transport mechanism
*/
-class UnixStreamFace : public StreamFace<boost::asio::local::stream_protocol>
+class UnixStreamFace : public StreamFace<boost::asio::local::stream_protocol, LocalFace>
{
public:
typedef boost::asio::local::stream_protocol protocol;
explicit
UnixStreamFace(const shared_ptr<protocol::socket>& socket);
-
- /** \brief Get whether face is connected to a local app
- *
- * Always true for a UnixStreamFace.
- */
- virtual bool
- isLocal() const;
};
} // namespace nfd
diff --git a/daemon/mgmt/internal-face.cpp b/daemon/mgmt/internal-face.cpp
index 1f1a6cb..707ee30 100644
--- a/daemon/mgmt/internal-face.cpp
+++ b/daemon/mgmt/internal-face.cpp
@@ -12,7 +12,7 @@
InternalFace::InternalFace()
{
-
+ setLocal(true);
}
void
@@ -98,12 +98,6 @@
throw Error("Internal face cannot be closed");
}
-bool
-InternalFace::isLocal() const
-{
- return true;
-}
-
void
InternalFace::setInterestFilter(const Name& filter,
OnInterest onInterest)
diff --git a/daemon/mgmt/internal-face.hpp b/daemon/mgmt/internal-face.hpp
index 0e17b3b..8d5805c 100644
--- a/daemon/mgmt/internal-face.hpp
+++ b/daemon/mgmt/internal-face.hpp
@@ -36,13 +36,6 @@
virtual void
close();
- /** \brief Get whether face is connected to a local app
- *
- * Always true for a InternalFace.
- */
- virtual bool
- isLocal() const;
-
// Methods implementing AppFace interface. Do not invoke from forwarder.
virtual void
diff --git a/daemon/mgmt/local-control-header-manager.cpp b/daemon/mgmt/local-control-header-manager.cpp
index 6a0f056..5717f54 100644
--- a/daemon/mgmt/local-control-header-manager.cpp
+++ b/daemon/mgmt/local-control-header-manager.cpp
@@ -5,6 +5,7 @@
*/
#include "local-control-header-manager.hpp"
+#include "face/local-face.hpp"
namespace nfd {
@@ -58,7 +59,15 @@
return;
}
- shared_ptr<Face> face = m_getFace(request.getIncomingFaceId());
+ shared_ptr<LocalFace> face =
+ dynamic_pointer_cast<LocalFace>(m_getFace(request.getIncomingFaceId()));
+
+ if (!static_cast<bool>(face))
+ {
+ NFD_LOG_INFO("command result: request to enable control header on non-local face");
+ sendResponse(command, 400, "Command not supported on the requested face");
+ return;
+ }
const Name::Component& module = command.get(COMMAND_PREFIX.size());
const Name::Component& verb = command.get(COMMAND_PREFIX.size() + 1);
diff --git a/daemon/mgmt/local-control-header-manager.hpp b/daemon/mgmt/local-control-header-manager.hpp
index ab3c08a..8c03e4e 100644
--- a/daemon/mgmt/local-control-header-manager.hpp
+++ b/daemon/mgmt/local-control-header-manager.hpp
@@ -23,7 +23,6 @@
void
onLocalControlHeaderRequest(const Interest& request);
-
private:
function<shared_ptr<Face>(FaceId)> m_getFace;