Merge remote-tracking branch 'named-data/master' into release-0.2.0
Change-Id: I086a5cce154fa6db26bb05d8f1e45715636c9656
diff --git a/src/common.hpp b/src/common.hpp
index 4a9914c..9d15e49 100644
--- a/src/common.hpp
+++ b/src/common.hpp
@@ -37,6 +37,12 @@
#define DEPRECATED(func) func
#endif
+namespace ndn {
+
+const size_t MAX_NDN_PACKET_SIZE = 8800;
+
+} // namespace ndn
+
#ifdef NDN_CXX_HAVE_CXX11
#if defined(__GNUC__)
@@ -49,7 +55,6 @@
# error "NDN-CXX library is configured and compiled in C++11 mode, but the current compiler is not C++11 enabled"
#endif // defined(__clang__) && (__cplusplus < 201103L)
-
#include <memory>
#include <functional>
@@ -60,6 +65,7 @@
using std::shared_ptr;
using std::weak_ptr;
+using std::bad_weak_ptr;
using std::make_shared;
using std::enable_shared_from_this;
@@ -102,6 +108,7 @@
using boost::shared_ptr;
using boost::weak_ptr;
+using boost::bad_weak_ptr;
using boost::make_shared;
using boost::enable_shared_from_this;
diff --git a/src/detail/face-impl.hpp b/src/detail/face-impl.hpp
index 7c259aa..187d7fa 100644
--- a/src/detail/face-impl.hpp
+++ b/src/detail/face-impl.hpp
@@ -137,6 +137,27 @@
m_pendingInterestTable.remove_if(MatchPendingInterestId(pendingInterestId));
}
+ void
+ asyncPutData(const shared_ptr<const Data>& data)
+ {
+ if (!m_face.m_transport->isConnected())
+ m_face.m_transport->connect(*m_face.m_ioService,
+ bind(&Face::onReceiveElement, &m_face, _1));
+
+ if (!m_face.m_transport->isExpectingData())
+ m_face.m_transport->resume();
+
+ if (!data->getLocalControlHeader().empty(false, true))
+ {
+ m_face.m_transport->send(data->getLocalControlHeader().wireEncode(*data, false, true),
+ data->wireEncode());
+ }
+ else
+ {
+ m_face.m_transport->send(data->wireEncode());
+ }
+ }
+
/////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/encoding/block.cpp b/src/encoding/block.cpp
index ed265b0..eeb0c3f 100644
--- a/src/encoding/block.cpp
+++ b/src/encoding/block.cpp
@@ -31,6 +31,7 @@
#include "buffer-stream.hpp"
#include <boost/lexical_cast.hpp>
+#include <boost/asio/buffer.hpp>
namespace ndn {
@@ -397,4 +398,10 @@
boost::lexical_cast<std::string>(type) + "] from Block");
}
+Block::operator boost::asio::const_buffer() const
+{
+ return boost::asio::const_buffer(wire(), size());
+}
+
+
} // namespace ndn
diff --git a/src/encoding/block.hpp b/src/encoding/block.hpp
index c91d12c..17192d8 100644
--- a/src/encoding/block.hpp
+++ b/src/encoding/block.hpp
@@ -29,6 +29,12 @@
#include "buffer.hpp"
#include "tlv.hpp"
+namespace boost {
+namespace asio {
+class const_buffer;
+} // namespace asio
+} // namespace boost
+
namespace ndn {
template<bool> class EncodingImpl;
@@ -281,6 +287,9 @@
bool
operator!=(const Block& other) const;
+public: // ConvertibleToConstBuffer
+ operator boost::asio::const_buffer() const;
+
protected:
ConstBufferPtr m_buffer;
diff --git a/src/encoding/tlv-nfd.hpp b/src/encoding/tlv-nfd.hpp
index 63776fb..ba00cad 100644
--- a/src/encoding/tlv-nfd.hpp
+++ b/src/encoding/tlv-nfd.hpp
@@ -55,10 +55,6 @@
NPitEntries = 133,
NMeasurementsEntries = 134,
NCsEntries = 135,
- NInInterests = 144,
- NInDatas = 145,
- NOutInterests = 146,
- NOutDatas = 147,
// Face Management
FaceStatus = 128,
@@ -68,12 +64,24 @@
FaceEventNotification = 192,
FaceEventKind = 193,
+ // ForwarderStatus and FaceStatus counters
+ NInInterests = 144,
+ NInDatas = 145,
+ NOutInterests = 146,
+ NOutDatas = 147,
+ NInBytes = 148,
+ NOutBytes = 149,
+
// FIB Management
FibEntry = 128,
NextHopRecord = 129,
// Strategy Choice Management
- StrategyChoice = 128
+ StrategyChoice = 128,
+
+ // RIB Management
+ RibEntry = 128,
+ Route = 129
};
@@ -89,7 +97,7 @@
namespace nfd {
-const uint64_t INVALID_FACE_ID = std::numeric_limits<uint64_t>::max();
+static const uint64_t INVALID_FACE_ID = std::numeric_limits<uint64_t>::max();
} // namespace nfd
diff --git a/src/face.cpp b/src/face.cpp
index 6f13570..f547f45 100644
--- a/src/face.cpp
+++ b/src/face.cpp
@@ -144,6 +144,10 @@
{
shared_ptr<Interest> interestToExpress = make_shared<Interest>(interest);
+ // Use `interestToExpress` to avoid wire format creation for the original Interest
+ if (interestToExpress->wireEncode().size() > MAX_NDN_PACKET_SIZE)
+ throw Error("Interest size exceeds maximum limit");
+
// If the same ioService thread, dispatch directly calls the method
m_ioService->dispatch(bind(&Impl::asyncExpressInterest, m_impl,
interestToExpress, onData, onTimeout));
@@ -165,19 +169,22 @@
void
Face::put(const Data& data)
{
- if (!m_transport->isConnected())
- m_transport->connect(*m_ioService,
- bind(&Face::onReceiveElement, this, _1));
+ // Use original `data`, since wire format should already exist for the original Data
+ if (data.wireEncode().size() > MAX_NDN_PACKET_SIZE)
+ throw Error("Data size exceeds maximum limit");
- if (!data.getLocalControlHeader().empty(false, true))
- {
- m_transport->send(data.getLocalControlHeader().wireEncode(data, false, true),
- data.wireEncode());
- }
- else
- {
- m_transport->send(data.wireEncode());
- }
+ shared_ptr<const Data> dataPtr;
+ try {
+ dataPtr = data.shared_from_this();
+ }
+ catch (const bad_weak_ptr& e) {
+ std::cerr << "Face::put WARNING: the supplied Data should be created using make_shared<Data>()"
+ << std::endl;
+ dataPtr = make_shared<Data>(data);
+ }
+
+ // If the same ioService thread, dispatch directly calls the method
+ m_ioService->dispatch(bind(&Impl::asyncPutData, m_impl, dataPtr));
}
void
@@ -186,8 +193,6 @@
m_ioService->post(bind(&Impl::asyncRemovePendingInterest, m_impl, pendingInterestId));
}
-
-
const RegisteredPrefixId*
Face::setInterestFilter(const InterestFilter& interestFilter,
const OnInterest& onInterest,
@@ -308,43 +313,40 @@
Face::processEvents(const time::milliseconds& timeout/* = time::milliseconds::zero()*/,
bool keepThread/* = false*/)
{
- try
- {
- if (timeout < time::milliseconds::zero())
- {
- // do not block if timeout is negative, but process pending events
- m_ioService->poll();
- return;
- }
-
- if (timeout > time::milliseconds::zero())
- {
- m_impl->m_processEventsTimeoutTimer->expires_from_now(time::milliseconds(timeout));
- m_impl->m_processEventsTimeoutTimer->async_wait(&fireProcessEventsTimeout);
- }
-
- if (keepThread) {
- // work will ensure that m_ioService is running until work object exists
- m_impl->m_ioServiceWork = make_shared<boost::asio::io_service::work>(ref(*m_ioService));
+ try {
+ if (timeout < time::milliseconds::zero())
+ {
+ // do not block if timeout is negative, but process pending events
+ m_ioService->poll();
+ return;
}
- m_ioService->run();
- m_ioService->reset(); // so it is possible to run processEvents again (if necessary)
+ if (timeout > time::milliseconds::zero())
+ {
+ m_impl->m_processEventsTimeoutTimer->expires_from_now(time::milliseconds(timeout));
+ m_impl->m_processEventsTimeoutTimer->async_wait(&fireProcessEventsTimeout);
+ }
+
+ if (keepThread) {
+ // work will ensure that m_ioService is running until work object exists
+ m_impl->m_ioServiceWork = make_shared<boost::asio::io_service::work>(ref(*m_ioService));
}
- catch (Face::ProcessEventsTimeout&)
- {
- // break
- m_impl->m_ioServiceWork.reset();
- m_ioService->reset();
- }
- catch (std::exception&)
- {
- m_impl->m_ioServiceWork.reset();
- m_ioService->reset();
- m_impl->m_pendingInterestTable.clear();
- m_impl->m_registeredPrefixTable.clear();
- throw;
- }
+
+ m_ioService->run();
+ m_ioService->reset(); // so it is possible to run processEvents again (if necessary)
+ }
+ catch (Face::ProcessEventsTimeout&) {
+ // break
+ m_impl->m_ioServiceWork.reset();
+ m_ioService->reset();
+ }
+ catch (...) {
+ m_impl->m_ioServiceWork.reset();
+ m_ioService->reset();
+ m_impl->m_pendingInterestTable.clear();
+ m_impl->m_registeredPrefixTable.clear();
+ throw;
+ }
}
void
diff --git a/src/face.hpp b/src/face.hpp
index a5ece29..9427b03 100644
--- a/src/face.hpp
+++ b/src/face.hpp
@@ -192,6 +192,8 @@
* @param onTimeout (optional) A function object to call if the interest times out
*
* @return The pending interest ID which can be used with removePendingInterest
+ *
+ * @throws Error when Interest size exceeds maximum limit (MAX_NDN_PACKET_SIZE)
*/
const PendingInterestId*
expressInterest(const Interest& interest,
@@ -206,6 +208,8 @@
* @param onTimeout (optional) A function object to call if the interest times out
*
* @return Opaque pending interest ID which can be used with removePendingInterest
+ *
+ * @throws Error when Interest size exceeds maximum limit (MAX_NDN_PACKET_SIZE)
*/
const PendingInterestId*
expressInterest(const Name& name,
@@ -440,7 +444,14 @@
* @brief Publish data packet
*
* This method can be called to satisfy the incoming Interest or to put Data packet into
- * the cache of the local NDN forwarder
+ * the cache of the local NDN forwarder.
+ *
+ * @param data Data packet to publish. It is highly recommended to use Data packet that
+ * was created using make_shared<Data>(...). Otherwise, put() will make an
+ * extra copy of the Data packet to ensure validity of published Data until
+ * asynchronous put() operation finishes.
+ *
+ * @throws Error when Data size exceeds maximum limit (MAX_NDN_PACKET_SIZE)
*/
void
put(const Data& data);
diff --git a/src/interest.cpp b/src/interest.cpp
index db3744c..f5ff57b 100644
--- a/src/interest.cpp
+++ b/src/interest.cpp
@@ -21,10 +21,9 @@
* Based on code originally written by Jeff Thompson <jefft0@remap.ucla.edu>
*/
-#include "common.hpp"
-
#include "interest.hpp"
#include "util/random.hpp"
+#include "util/crypto.hpp"
#include "data.hpp"
namespace ndn {
@@ -102,10 +101,69 @@
bool
Interest::matchesData(const Data& data) const
{
- if (!this->matchesName(data.getFullName())) {
+ size_t interestNameLength = m_name.size();
+ const Name& dataName = data.getName();
+ size_t fullNameLength = dataName.size() + 1;
+
+ // check MinSuffixComponents
+ bool hasMinSuffixComponents = getMinSuffixComponents() >= 0;
+ size_t minSuffixComponents = hasMinSuffixComponents ?
+ static_cast<size_t>(getMinSuffixComponents()) : 0;
+ if (!(interestNameLength + minSuffixComponents <= fullNameLength))
return false;
+
+ // check MaxSuffixComponents
+ bool hasMaxSuffixComponents = getMaxSuffixComponents() >= 0;
+ if (hasMaxSuffixComponents &&
+ !(interestNameLength + getMaxSuffixComponents() >= fullNameLength))
+ return false;
+
+ // check prefix
+ if (interestNameLength == fullNameLength) {
+ bool mightEndWithDigest = (interestNameLength > 0) &&
+ (m_name.get(-1).value_size() == crypto::SHA256_DIGEST_SIZE);
+ if (mightEndWithDigest) {
+ // Interest Name is same length as Data full Name, last component could match digest
+ if (!m_name.isPrefixOf(data.getFullName()))
+ return false;
+ }
+ else {
+ // Interest Name is same length as Data full Name, but last component isn't digest
+ // so there's no possibility of matching
+ return false;
+ }
+ }
+ else {
+ // Interest Name is a strict prefix of Data full Name
+ if (!m_name.isPrefixOf(dataName))
+ return false;
}
+ // check Exclude
+ // Exclude won't be violated if Interest Name is same as Data full Name
+ if (!getExclude().empty() && fullNameLength > interestNameLength) {
+ if (interestNameLength == fullNameLength - 1) {
+ // component to exclude is the digest
+ if (getExclude().isExcluded(data.getFullName().get(interestNameLength)))
+ return false;
+ // There's opportunity to inspect the Exclude filter and determine whether
+ // the digest would make a difference.
+ // eg. "Exclude=<Any>AA" won't exclude any digest - fullName not needed
+ // "Exclude=ZZ<Any>" excludes all digests - fullName not needed
+ // "Exclude=<Any>80000000000000000000000000000000"
+ // excludes half of the digests - fullName required
+ // But Interests that contain the exact Data Name before digest and also
+ // contain Exclude filter is too rare to optimize for, so we request
+ // fullName no mater what's in the Exclude filter.
+ }
+ else {
+ // component to exclude is not the digest
+ if (getExclude().isExcluded(dataName.get(interestNameLength)))
+ return false;
+ }
+ }
+
+ // check PublisherPublicKeyLocator
const KeyLocator& publisherPublicKeyLocator = this->getPublisherPublicKeyLocator();
if (!publisherPublicKeyLocator.empty()) {
const Signature& signature = data.getSignature();
diff --git a/src/management/nfd-control-command.hpp b/src/management/nfd-control-command.hpp
index 0068317..252812c 100644
--- a/src/management/nfd-control-command.hpp
+++ b/src/management/nfd-control-command.hpp
@@ -495,7 +495,7 @@
.required(CONTROL_PARAMETER_ORIGIN)
.required(CONTROL_PARAMETER_COST)
.required(CONTROL_PARAMETER_FLAGS)
- .required(CONTROL_PARAMETER_EXPIRATION_PERIOD);
+ .optional(CONTROL_PARAMETER_EXPIRATION_PERIOD);
}
virtual void
@@ -513,14 +513,6 @@
if (!parameters.hasFlags()) {
parameters.setFlags(ROUTE_FLAG_CHILD_INHERIT);
}
- if (!parameters.hasExpirationPeriod()) {
- if (parameters.getFaceId() == 0) {
- parameters.setExpirationPeriod(time::milliseconds::max());
- }
- else {
- parameters.setExpirationPeriod(time::hours(1));
- }
- }
}
virtual void
diff --git a/src/management/nfd-face-status.cpp b/src/management/nfd-face-status.cpp
new file mode 100644
index 0000000..adf29c2
--- /dev/null
+++ b/src/management/nfd-face-status.cpp
@@ -0,0 +1,227 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library 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 Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "nfd-face-status.hpp"
+
+namespace ndn {
+namespace nfd {
+
+FaceStatus::FaceStatus()
+ : m_faceId(0)
+ , m_hasExpirationPeriod(false)
+ , m_flags(0)
+ , m_nInInterests(0)
+ , m_nInDatas(0)
+ , m_nOutInterests(0)
+ , m_nOutDatas(0)
+ , m_nInBytes(0)
+ , m_nOutBytes(0)
+{
+}
+
+template<bool T>
+size_t
+FaceStatus::wireEncode(EncodingImpl<T>& encoder) const
+{
+ size_t totalLength = 0;
+
+ totalLength += prependNonNegativeIntegerBlock(encoder,
+ tlv::nfd::NOutBytes, m_nOutBytes);
+ totalLength += prependNonNegativeIntegerBlock(encoder,
+ tlv::nfd::NInBytes, m_nInBytes);
+ totalLength += prependNonNegativeIntegerBlock(encoder,
+ tlv::nfd::NOutDatas, m_nOutDatas);
+ totalLength += prependNonNegativeIntegerBlock(encoder,
+ tlv::nfd::NOutInterests, m_nOutInterests);
+ totalLength += prependNonNegativeIntegerBlock(encoder,
+ tlv::nfd::NInDatas, m_nInDatas);
+ totalLength += prependNonNegativeIntegerBlock(encoder,
+ tlv::nfd::NInInterests, m_nInInterests);
+ totalLength += prependNonNegativeIntegerBlock(encoder,
+ tlv::nfd::FaceFlags, m_flags);
+ if (m_hasExpirationPeriod) {
+ totalLength += prependNonNegativeIntegerBlock(encoder,
+ tlv::nfd::ExpirationPeriod, m_expirationPeriod.count());
+ }
+ totalLength += prependByteArrayBlock(encoder, tlv::nfd::LocalUri,
+ reinterpret_cast<const uint8_t*>(m_localUri.c_str()), m_localUri.size());
+ totalLength += prependByteArrayBlock(encoder, tlv::nfd::Uri,
+ reinterpret_cast<const uint8_t*>(m_remoteUri.c_str()), m_remoteUri.size());
+ totalLength += prependNonNegativeIntegerBlock(encoder,
+ tlv::nfd::FaceId, m_faceId);
+
+ totalLength += encoder.prependVarNumber(totalLength);
+ totalLength += encoder.prependVarNumber(tlv::nfd::FaceStatus);
+ return totalLength;
+}
+
+template size_t
+FaceStatus::wireEncode<true>(EncodingImpl<true>& block) const;
+
+template size_t
+FaceStatus::wireEncode<false>(EncodingImpl<false>& block) const;
+
+const Block&
+FaceStatus::wireEncode() const
+{
+ if (m_wire.hasWire())
+ return m_wire;
+
+ EncodingEstimator estimator;
+ size_t estimatedSize = wireEncode(estimator);
+
+ EncodingBuffer buffer(estimatedSize, 0);
+ wireEncode(buffer);
+
+ m_wire = buffer.block();
+ return m_wire;
+}
+
+void
+FaceStatus::wireDecode(const Block& block)
+{
+ if (block.type() != tlv::nfd::FaceStatus) {
+ throw Error("expecting FaceStatus block");
+ }
+ m_wire = block;
+ m_wire.parse();
+ Block::element_const_iterator val = m_wire.elements_begin();
+
+ if (val != m_wire.elements_end() && val->type() == tlv::nfd::FaceId) {
+ m_faceId = readNonNegativeInteger(*val);
+ ++val;
+ }
+ else {
+ throw Error("missing required FaceId field");
+ }
+
+ if (val != m_wire.elements_end() && val->type() == tlv::nfd::Uri) {
+ m_remoteUri.assign(reinterpret_cast<const char*>(val->value()), val->value_size());
+ ++val;
+ }
+ else {
+ throw Error("missing required Uri field");
+ }
+
+ if (val != m_wire.elements_end() && val->type() == tlv::nfd::LocalUri) {
+ m_localUri.assign(reinterpret_cast<const char*>(val->value()), val->value_size());
+ ++val;
+ }
+ else {
+ throw Error("missing required LocalUri field");
+ }
+
+ if (val != m_wire.elements_end() && val->type() == tlv::nfd::ExpirationPeriod) {
+ m_expirationPeriod = time::milliseconds(readNonNegativeInteger(*val));
+ m_hasExpirationPeriod = true;
+ ++val;
+ }
+ else {
+ m_hasExpirationPeriod = false;
+ // ExpirationPeriod is optional
+ }
+
+ if (val != m_wire.elements_end() && val->type() == tlv::nfd::FaceFlags) {
+ m_flags = readNonNegativeInteger(*val);
+ ++val;
+ }
+ else {
+ throw Error("missing required FaceFlags field");
+ }
+
+ if (val != m_wire.elements_end() && val->type() == tlv::nfd::NInInterests) {
+ m_nInInterests = readNonNegativeInteger(*val);
+ ++val;
+ }
+ else {
+ throw Error("missing required NInInterests field");
+ }
+
+ if (val != m_wire.elements_end() && val->type() == tlv::nfd::NInDatas) {
+ m_nInDatas = readNonNegativeInteger(*val);
+ ++val;
+ }
+ else {
+ throw Error("missing required NInDatas field");
+ }
+
+ if (val != m_wire.elements_end() && val->type() == tlv::nfd::NOutInterests) {
+ m_nOutInterests = readNonNegativeInteger(*val);
+ ++val;
+ }
+ else {
+ throw Error("missing required NOutInterests field");
+ }
+
+ if (val != m_wire.elements_end() && val->type() == tlv::nfd::NOutDatas) {
+ m_nOutDatas = readNonNegativeInteger(*val);
+ ++val;
+ }
+ else {
+ throw Error("missing required NOutDatas field");
+ }
+
+ if (val != m_wire.elements_end() && val->type() == tlv::nfd::NInBytes) {
+ m_nInBytes = readNonNegativeInteger(*val);
+ ++val;
+ }
+ else {
+ throw Error("missing required NInBytes field");
+ }
+
+ if (val != m_wire.elements_end() && val->type() == tlv::nfd::NOutBytes) {
+ m_nOutBytes = readNonNegativeInteger(*val);
+ ++val;
+ }
+ else {
+ throw Error("missing required NOutBytes field");
+ }
+}
+
+std::ostream&
+operator<<(std::ostream& os, const FaceStatus& status)
+{
+ os << "FaceStatus("
+ << "FaceID: " << status.getFaceId() << ",\n"
+ << "RemoteUri: " << status.getRemoteUri() << ",\n"
+ << "LocalUri: " << status.getLocalUri() << ",\n";
+
+ if (status.hasExpirationPeriod()) {
+ os << "ExpirationPeriod: " << status.getExpirationPeriod() << ",\n";
+ }
+ else {
+ os << "ExpirationPeriod: infinite,\n";
+ }
+
+ os << "Flags: " << status.getFlags() << ",\n"
+ << "Counters: { Interests: {in: " << status.getNInInterests() << ", "
+ << "out: " << status.getNOutInterests() << "},\n"
+ << " Data: {in: " << status.getNInDatas() << ", "
+ << "out: " << status.getNOutDatas() << "},\n"
+ << " bytes: {in: " << status.getNInBytes() << ", "
+ << "out: " << status.getNOutBytes() << "} }\n"
+ << ")";
+ return os;
+}
+
+} // namespace nfd
+} // namespace ndn
+
diff --git a/src/management/nfd-face-status.hpp b/src/management/nfd-face-status.hpp
index a92e154..1b33dea 100644
--- a/src/management/nfd-face-status.hpp
+++ b/src/management/nfd-face-status.hpp
@@ -209,6 +209,34 @@
return *this;
}
+ uint64_t
+ getNInBytes() const
+ {
+ return m_nInBytes;
+ }
+
+ FaceStatus&
+ setNInBytes(uint64_t nInBytes)
+ {
+ m_wire.reset();
+ m_nInBytes = nInBytes;
+ return *this;
+ }
+
+ uint64_t
+ getNOutBytes() const
+ {
+ return m_nOutBytes;
+ }
+
+ FaceStatus&
+ setNOutBytes(uint64_t nOutBytes)
+ {
+ m_wire.reset();
+ m_nOutBytes = nOutBytes;
+ return *this;
+ }
+
private:
uint64_t m_faceId;
std::string m_remoteUri;
@@ -220,176 +248,14 @@
uint64_t m_nInDatas;
uint64_t m_nOutInterests;
uint64_t m_nOutDatas;
+ uint64_t m_nInBytes;
+ uint64_t m_nOutBytes;
mutable Block m_wire;
};
-inline
-FaceStatus::FaceStatus()
- : m_faceId(0)
- , m_hasExpirationPeriod(false)
- , m_flags(0)
- , m_nInInterests(0)
- , m_nInDatas(0)
- , m_nOutInterests(0)
- , m_nOutDatas(0)
-{
-}
-
-template<bool T>
-inline size_t
-FaceStatus::wireEncode(EncodingImpl<T>& encoder) const
-{
- size_t totalLength = 0;
-
- totalLength += prependNonNegativeIntegerBlock(encoder,
- tlv::nfd::NOutDatas, m_nOutDatas);
- totalLength += prependNonNegativeIntegerBlock(encoder,
- tlv::nfd::NOutInterests, m_nOutInterests);
- totalLength += prependNonNegativeIntegerBlock(encoder,
- tlv::nfd::NInDatas, m_nInDatas);
- totalLength += prependNonNegativeIntegerBlock(encoder,
- tlv::nfd::NInInterests, m_nInInterests);
- totalLength += prependNonNegativeIntegerBlock(encoder,
- tlv::nfd::FaceFlags, m_flags);
- if (m_hasExpirationPeriod) {
- totalLength += prependNonNegativeIntegerBlock(encoder,
- tlv::nfd::ExpirationPeriod, m_expirationPeriod.count());
- }
- totalLength += prependByteArrayBlock(encoder, tlv::nfd::LocalUri,
- reinterpret_cast<const uint8_t*>(m_localUri.c_str()), m_localUri.size());
- totalLength += prependByteArrayBlock(encoder, tlv::nfd::Uri,
- reinterpret_cast<const uint8_t*>(m_remoteUri.c_str()), m_remoteUri.size());
- totalLength += prependNonNegativeIntegerBlock(encoder,
- tlv::nfd::FaceId, m_faceId);
-
- totalLength += encoder.prependVarNumber(totalLength);
- totalLength += encoder.prependVarNumber(tlv::nfd::FaceStatus);
- return totalLength;
-}
-
-inline const Block&
-FaceStatus::wireEncode() const
-{
- if (m_wire.hasWire())
- return m_wire;
-
- EncodingEstimator estimator;
- size_t estimatedSize = wireEncode(estimator);
-
- EncodingBuffer buffer(estimatedSize, 0);
- wireEncode(buffer);
-
- m_wire = buffer.block();
- return m_wire;
-}
-
-inline void
-FaceStatus::wireDecode(const Block& block)
-{
- if (block.type() != tlv::nfd::FaceStatus) {
- throw Error("expecting FaceStatus block");
- }
- m_wire = block;
- m_wire.parse();
- Block::element_const_iterator val = m_wire.elements_begin();
-
- if (val != m_wire.elements_end() && val->type() == tlv::nfd::FaceId) {
- m_faceId = readNonNegativeInteger(*val);
- ++val;
- }
- else {
- throw Error("missing required FaceId field");
- }
-
- if (val != m_wire.elements_end() && val->type() == tlv::nfd::Uri) {
- m_remoteUri.assign(reinterpret_cast<const char*>(val->value()), val->value_size());
- ++val;
- }
- else {
- throw Error("missing required Uri field");
- }
-
- if (val != m_wire.elements_end() && val->type() == tlv::nfd::LocalUri) {
- m_localUri.assign(reinterpret_cast<const char*>(val->value()), val->value_size());
- ++val;
- }
- else {
- throw Error("missing required LocalUri field");
- }
-
- if (val != m_wire.elements_end() && val->type() == tlv::nfd::ExpirationPeriod) {
- m_expirationPeriod = time::milliseconds(readNonNegativeInteger(*val));
- m_hasExpirationPeriod = true;
- ++val;
- }
- else {
- m_hasExpirationPeriod = false;
- // ExpirationPeriod is optional
- }
-
- if (val != m_wire.elements_end() && val->type() == tlv::nfd::FaceFlags) {
- m_flags = readNonNegativeInteger(*val);
- ++val;
- }
- else {
- throw Error("missing required FaceFlags field");
- }
-
- if (val != m_wire.elements_end() && val->type() == tlv::nfd::NInInterests) {
- m_nInInterests = readNonNegativeInteger(*val);
- ++val;
- }
- else {
- throw Error("missing required NInInterests field");
- }
-
- if (val != m_wire.elements_end() && val->type() == tlv::nfd::NInDatas) {
- m_nInDatas = readNonNegativeInteger(*val);
- ++val;
- }
- else {
- throw Error("missing required NInDatas field");
- }
-
- if (val != m_wire.elements_end() && val->type() == tlv::nfd::NOutInterests) {
- m_nOutInterests = readNonNegativeInteger(*val);
- ++val;
- }
- else {
- throw Error("missing required NOutInterests field");
- }
-
- if (val != m_wire.elements_end() && val->type() == tlv::nfd::NOutDatas) {
- m_nOutDatas = readNonNegativeInteger(*val);
- ++val;
- }
- else {
- throw Error("missing required NOutDatas field");
- }
-}
-
-inline std::ostream&
-operator<<(std::ostream& os, const FaceStatus& status)
-{
- os << "FaceStatus("
- << "FaceID: " << status.getFaceId() << ", "
- << "RemoteUri: " << status.getRemoteUri() << ", "
- << "LocalUri: " << status.getLocalUri() << ", ";
-
- if (status.hasExpirationPeriod()) {
- os << "ExpirationPeriod: " << status.getExpirationPeriod() << ", ";
- }
- else {
- os << "ExpirationPeriod: infinite, ";
- }
-
- os << "Flags: " << status.getFlags() << ", "
- << "Counters: " << status.getNInInterests() << "|" << status.getNInDatas()
- << "|" << status.getNOutInterests() << "|" << status.getNOutDatas()
- << ")";
- return os;
-}
+std::ostream&
+operator<<(std::ostream& os, const FaceStatus& status);
} // namespace nfd
} // namespace ndn
diff --git a/src/management/nfd-rib-entry.cpp b/src/management/nfd-rib-entry.cpp
new file mode 100644
index 0000000..d075cc6
--- /dev/null
+++ b/src/management/nfd-rib-entry.cpp
@@ -0,0 +1,307 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library 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 Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "nfd-rib-entry.hpp"
+
+#include "management/nfd-control-command.hpp"
+
+namespace ndn {
+namespace nfd {
+
+const time::milliseconds Route::INFINITE_EXPIRATION_PERIOD(time::milliseconds::max());
+
+Route::Route()
+ : m_faceId(0)
+ , m_origin(0)
+ , m_cost(0)
+ , m_flags(ROUTE_FLAG_CHILD_INHERIT)
+ , m_expirationPeriod(INFINITE_EXPIRATION_PERIOD)
+ , m_hasInfiniteExpirationPeriod(true)
+{
+}
+
+Route::Route(const Block& block)
+{
+ wireDecode(block);
+}
+
+template<bool T>
+size_t
+Route::wireEncode(EncodingImpl<T>& block) const
+{
+ size_t totalLength = 0;
+
+ // Absence of an ExpirationPeriod signifies non-expiration
+ if (!m_hasInfiniteExpirationPeriod) {
+ totalLength += prependNonNegativeIntegerBlock(block,
+ ndn::tlv::nfd::ExpirationPeriod,
+ m_expirationPeriod.count());
+ }
+
+ totalLength += prependNonNegativeIntegerBlock(block,
+ ndn::tlv::nfd::Flags,
+ m_flags);
+
+ totalLength += prependNonNegativeIntegerBlock(block,
+ ndn::tlv::nfd::Cost,
+ m_cost);
+
+ totalLength += prependNonNegativeIntegerBlock(block,
+ ndn::tlv::nfd::Origin,
+ m_origin);
+
+ totalLength += prependNonNegativeIntegerBlock(block,
+ ndn::tlv::nfd::FaceId,
+ m_faceId);
+
+ totalLength += block.prependVarNumber(totalLength);
+ totalLength += block.prependVarNumber(ndn::tlv::nfd::Route);
+
+ return totalLength;
+}
+
+template size_t
+Route::wireEncode<true>(EncodingImpl<true>& block) const;
+
+template size_t
+Route::wireEncode<false>(EncodingImpl<false>& block) const;
+
+const Block&
+Route::wireEncode() const
+{
+ if (m_wire.hasWire()) {
+ return m_wire;
+ }
+
+ EncodingEstimator estimator;
+ size_t estimatedSize = wireEncode(estimator);
+
+ EncodingBuffer buffer(estimatedSize, 0);
+ wireEncode(buffer);
+
+ m_wire = buffer.block();
+
+ return m_wire;
+}
+
+void
+Route::wireDecode(const Block& wire)
+{
+ m_faceId = 0;
+ m_origin = 0;
+ m_cost = 0;
+ m_flags = 0;
+ m_expirationPeriod = time::milliseconds::min();
+
+ m_wire = wire;
+
+ if (m_wire.type() != tlv::nfd::Route) {
+ std::stringstream error;
+ error << "Expected Route Block, but Block is of a different type: #"
+ << m_wire.type();
+ throw Error(error.str());
+ }
+
+ m_wire.parse();
+
+ Block::element_const_iterator val = m_wire.elements_begin();
+
+ if (val != m_wire.elements_end() && val->type() == tlv::nfd::FaceId) {
+ m_faceId = readNonNegativeInteger(*val);
+ ++val;
+ }
+ else {
+ throw Error("Missing required FaceId field");
+ }
+
+ if (val != m_wire.elements_end() && val->type() == tlv::nfd::Origin) {
+ m_origin = readNonNegativeInteger(*val);
+ ++val;
+ }
+ else {
+ throw Error("Missing required Origin field");
+ }
+
+ if (val != m_wire.elements_end() && val->type() == tlv::nfd::Cost) {
+ m_cost = readNonNegativeInteger(*val);
+ ++val;
+ }
+ else {
+ throw Error("Missing required Cost field");
+ }
+
+ if (val != m_wire.elements_end() && val->type() == tlv::nfd::Flags) {
+ m_flags = readNonNegativeInteger(*val);
+ ++val;
+ }
+ else {
+ throw Error("Missing required Flags field");
+ }
+
+ if (val != m_wire.elements_end() && val->type() == tlv::nfd::ExpirationPeriod) {
+ m_expirationPeriod = time::milliseconds(readNonNegativeInteger(*val));
+ m_hasInfiniteExpirationPeriod = false;
+ }
+ else {
+ m_expirationPeriod = INFINITE_EXPIRATION_PERIOD;
+ m_hasInfiniteExpirationPeriod = true;
+ }
+}
+
+std::ostream&
+operator<<(std::ostream& os, const Route& route)
+{
+ os << "Route("
+ << "FaceId: " << route.getFaceId() << ", "
+ << "Origin: " << route.getOrigin() << ", "
+ << "Cost: " << route.getCost() << ", "
+ << "Flags: " << route.getFlags() << ", ";
+
+ if (!route.hasInfiniteExpirationPeriod()) {
+ os << "ExpirationPeriod: " << route.getExpirationPeriod();
+ }
+ else {
+ os << "ExpirationPeriod: Infinity";
+ }
+
+ os << ")";
+
+ return os;
+}
+
+
+//////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////
+
+
+RibEntry::RibEntry()
+{
+}
+
+RibEntry::RibEntry(const Block& block)
+{
+ wireDecode(block);
+}
+
+
+template<bool T>
+size_t
+RibEntry::wireEncode(EncodingImpl<T>& block) const
+{
+ size_t totalLength = 0;
+
+ for (std::list<Route>::const_reverse_iterator it = m_routes.rbegin();
+ it != m_routes.rend(); ++it)
+ {
+ totalLength += it->wireEncode(block);
+ }
+
+ totalLength += m_prefix.wireEncode(block);
+
+ totalLength += block.prependVarNumber(totalLength);
+ totalLength += block.prependVarNumber(tlv::nfd::RibEntry);
+
+ return totalLength;
+}
+
+template size_t
+RibEntry::wireEncode<true>(EncodingImpl<true>& block) const;
+
+template size_t
+RibEntry::wireEncode<false>(EncodingImpl<false>& block) const;
+
+const Block&
+RibEntry::wireEncode() const
+{
+ if (m_wire.hasWire()) {
+ return m_wire;
+ }
+
+ EncodingEstimator estimator;
+ size_t estimatedSize = wireEncode(estimator);
+
+ EncodingBuffer buffer(estimatedSize, 0);
+ wireEncode(buffer);
+
+ m_wire = buffer.block();
+
+ return m_wire;
+}
+
+void
+RibEntry::wireDecode(const Block& wire)
+{
+ m_prefix.clear();
+ m_routes.clear();
+
+ m_wire = wire;
+
+ if (m_wire.type() != tlv::nfd::RibEntry) {
+ std::stringstream error;
+ error << "Expected RibEntry Block, but Block is of a different type: #"
+ << m_wire.type();
+ throw Error(error.str());
+ }
+
+ m_wire.parse();
+
+ Block::element_const_iterator val = m_wire.elements_begin();
+
+ if (val != m_wire.elements_end() && val->type() == Tlv::Name) {
+ m_prefix.wireDecode(*val);
+ ++val;
+ }
+ else {
+ throw Error("Missing required Name field");
+ }
+
+ for (; val != m_wire.elements_end(); ++val) {
+
+ if (val->type() == tlv::nfd::Route) {
+ m_routes.push_back(Route(*val));
+ }
+ else {
+ std::stringstream error;
+ error << "Expected Route Block, but Block is of a different type: #"
+ << m_wire.type();
+ throw Error(error.str());
+ }
+ }
+}
+
+std::ostream&
+operator<<(std::ostream& os, const RibEntry& entry)
+{
+ os << "RibEntry{\n"
+ << " Name: " << entry.getName() << "\n";
+
+ for (RibEntry::iterator it = entry.begin(); it != entry.end(); ++it) {
+ os << " " << *it << "\n";
+ }
+
+ os << "}";
+
+ return os;
+}
+
+} // namespace nfd
+} // namespace ndn
diff --git a/src/management/nfd-rib-entry.hpp b/src/management/nfd-rib-entry.hpp
new file mode 100644
index 0000000..9ea84c2
--- /dev/null
+++ b/src/management/nfd-rib-entry.hpp
@@ -0,0 +1,282 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library 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 Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDN_MANAGEMENT_NFD_RIB_ENTRY_HPP
+#define NDN_MANAGEMENT_NFD_RIB_ENTRY_HPP
+
+#include "../encoding/block.hpp"
+#include "../encoding/encoding-buffer.hpp"
+#include "../encoding/tlv-nfd.hpp"
+#include "../name.hpp"
+
+#include <list>
+
+namespace ndn {
+namespace nfd {
+
+/**
+ * @ingroup management
+ *
+ * @brief Data abstraction for Route
+ *
+ * A route indicates the availability of content via a certain face and
+ * provides meta-information about the face.
+ *
+ * Route := ROUTE-TYPE TLV-LENGTH
+ * FaceId
+ * Origin
+ * Cost
+ * Flags
+ * ExpirationPeriod?
+ *
+ * @sa http://redmine.named-data.net/projects/nfd/wiki/RibMgmt
+ */
+class Route
+{
+public:
+ class Error : public Tlv::Error
+ {
+ public:
+ explicit
+ Error(const std::string& what) : Tlv::Error(what)
+ {
+ }
+ };
+
+ Route();
+
+ explicit
+ Route(const Block& block);
+
+ uint64_t
+ getFaceId() const
+ {
+ return m_faceId;
+ }
+
+ Route&
+ setFaceId(uint64_t faceId)
+ {
+ m_faceId = faceId;
+ m_wire.reset();
+ return *this;
+ }
+
+ uint64_t
+ getOrigin() const
+ {
+ return m_origin;
+ }
+
+ Route&
+ setOrigin(uint64_t origin)
+ {
+ m_origin = origin;
+ m_wire.reset();
+ return *this;
+ }
+
+ uint64_t
+ getCost() const
+ {
+ return m_cost;
+ }
+
+ Route&
+ setCost(uint64_t cost)
+ {
+ m_cost = cost;
+ m_wire.reset();
+ return *this;
+ }
+
+ uint64_t
+ getFlags() const
+ {
+ return m_flags;
+ }
+
+ Route&
+ setFlags(uint64_t flags)
+ {
+ m_flags = flags;
+ m_wire.reset();
+ return *this;
+ }
+
+ static const time::milliseconds INFINITE_EXPIRATION_PERIOD;
+
+ const time::milliseconds&
+ getExpirationPeriod() const
+ {
+ return m_expirationPeriod;
+ }
+
+ Route&
+ setExpirationPeriod(const time::milliseconds& expirationPeriod)
+ {
+ m_expirationPeriod = expirationPeriod;
+
+ m_hasInfiniteExpirationPeriod = m_expirationPeriod == INFINITE_EXPIRATION_PERIOD;
+
+ m_wire.reset();
+ return *this;
+ }
+
+ bool
+ hasInfiniteExpirationPeriod() const
+ {
+ return m_hasInfiniteExpirationPeriod;
+ }
+
+ template<bool T>
+ size_t
+ wireEncode(EncodingImpl<T>& block) const;
+
+ const Block&
+ wireEncode() const;
+
+ void
+ wireDecode(const Block& wire);
+
+private:
+ uint64_t m_faceId;
+ uint64_t m_origin;
+ uint64_t m_cost;
+ uint64_t m_flags;
+ time::milliseconds m_expirationPeriod;
+ bool m_hasInfiniteExpirationPeriod;
+
+ mutable Block m_wire;
+};
+
+std::ostream&
+operator<<(std::ostream& os, const Route& route);
+
+/**
+ * @ingroup management
+ *
+ * @brief Data abstraction for RIB entry
+ *
+ * A RIB entry contains one or more routes for the name prefix
+ *
+ * RibEntry := RIB-ENTRY-TYPE TLV-LENGTH
+ * Name
+ * Route+
+ *
+ * @sa http://redmine.named-data.net/projects/nfd/wiki/RibMgmt
+ */
+class RibEntry
+{
+public:
+ class Error : public Tlv::Error
+ {
+ public:
+ Error(const std::string& what) : Tlv::Error(what)
+ {
+ }
+ };
+
+ typedef std::list<Route> RouteList;
+ typedef RouteList::const_iterator iterator;
+
+ RibEntry();
+
+ explicit
+ RibEntry(const Block& block);
+
+ const Name&
+ getName() const
+ {
+ return m_prefix;
+ }
+
+ RibEntry&
+ setName(const Name& prefix)
+ {
+ m_prefix = prefix;
+ m_wire.reset();
+ return *this;
+ }
+
+ const std::list<Route>&
+ getRoutes() const
+ {
+ return m_routes;
+ }
+
+ RibEntry&
+ addRoute(const Route& route)
+ {
+ m_routes.push_back(route);
+ m_wire.reset();
+ return *this;
+ }
+
+ RibEntry&
+ clearRoutes()
+ {
+ m_routes.clear();
+ return *this;
+ }
+
+ template<bool T>
+ size_t
+ wireEncode(EncodingImpl<T>& block) const;
+
+ const Block&
+ wireEncode() const;
+
+ void
+ wireDecode(const Block& wire);
+
+ iterator
+ begin() const;
+
+ iterator
+ end() const;
+
+private:
+ Name m_prefix;
+ RouteList m_routes;
+
+ mutable Block m_wire;
+};
+
+inline RibEntry::iterator
+RibEntry::begin() const
+{
+ return m_routes.begin();
+}
+
+inline RibEntry::iterator
+RibEntry::end() const
+{
+ return m_routes.end();
+}
+
+std::ostream&
+operator<<(std::ostream& os, const RibEntry& entry);
+
+} // namespace nfd
+} // namespace ndn
+
+#endif // NDN_MANAGEMENT_NFD_RIB_ENTRY_HPP
diff --git a/src/transport/stream-transport.hpp b/src/transport/stream-transport.hpp
index 04aeac3..9bb5b7b 100644
--- a/src/transport/stream-transport.hpp
+++ b/src/transport/stream-transport.hpp
@@ -28,17 +28,16 @@
namespace ndn {
-const size_t MAX_LENGTH = 9000;
-
template<class BaseTransport, class Protocol>
class StreamTransportImpl
{
public:
- typedef BaseTransport base_transport;
- typedef Protocol protocol;
- typedef StreamTransportImpl<BaseTransport,Protocol> impl;
+ typedef StreamTransportImpl<BaseTransport,Protocol> Impl;
- StreamTransportImpl(base_transport& transport, boost::asio::io_service& ioService)
+ typedef std::list<Block> BlockSequence;
+ typedef std::list<BlockSequence> TransmissionQueue;
+
+ StreamTransportImpl(BaseTransport& transport, boost::asio::io_service& ioService)
: m_transport(transport)
, m_socket(ioService)
, m_inputBufferSize(0)
@@ -58,23 +57,11 @@
resume();
m_transport.m_isConnected = true;
- for (std::list<Block>::iterator i = m_sendQueue.begin(); i != m_sendQueue.end(); ++i)
- m_socket.async_send(boost::asio::buffer(i->wire(), i->size()),
- bind(&impl::handle_async_send, this, _1, *i));
-
- for (std::list< std::pair<Block,Block> >::iterator i = m_sendPairQueue.begin();
- i != m_sendPairQueue.end(); ++i)
- {
- std::vector<boost::asio::const_buffer> buffer;
- buffer.reserve(2);
- buffer.push_back(boost::asio::buffer(i->first.wire(), i->first.size()));
- buffer.push_back(boost::asio::buffer(i->second.wire(), i->second.size()));
- m_socket.async_send(buffer,
- bind(&impl::handle_async_send2, this, _1, i->first, i->second));
- }
-
- m_sendQueue.clear();
- m_sendPairQueue.clear();
+ if (!m_transmissionQueue.empty()) {
+ boost::asio::async_write(m_socket, *m_transmissionQueue.begin(),
+ bind(&Impl::handleAsyncWrite, this, _1,
+ m_transmissionQueue.begin()));
+ }
}
else
{
@@ -96,19 +83,19 @@
}
void
- connect(const typename protocol::endpoint& endpoint)
+ connect(const typename Protocol::endpoint& endpoint)
{
if (!m_connectionInProgress) {
m_connectionInProgress = true;
- // Wait at most 4 time::seconds to connect
+ // Wait at most 4 seconds to connect
/// @todo Decide whether this number should be configurable
m_connectTimer.expires_from_now(boost::posix_time::seconds(4));
- m_connectTimer.async_wait(bind(&impl::connectTimeoutHandler, this, _1));
+ m_connectTimer.async_wait(bind(&Impl::connectTimeoutHandler, this, _1));
m_socket.open();
m_socket.async_connect(endpoint,
- bind(&impl::connectHandler, this, _1));
+ bind(&Impl::connectHandler, this, _1));
}
}
@@ -124,8 +111,7 @@
m_transport.m_isConnected = false;
m_transport.m_isExpectingData = false;
- m_sendQueue.clear();
- m_sendPairQueue.clear();
+ m_transmissionQueue.clear();
}
void
@@ -151,47 +137,77 @@
{
m_transport.m_isExpectingData = true;
m_inputBufferSize = 0;
- m_socket.async_receive(boost::asio::buffer(m_inputBuffer, MAX_LENGTH), 0,
- bind(&impl::handle_async_receive, this, _1, _2));
+ m_socket.async_receive(boost::asio::buffer(m_inputBuffer, MAX_NDN_PACKET_SIZE), 0,
+ bind(&Impl::handleAsyncReceive, this, _1, _2));
}
}
void
send(const Block& wire)
{
- if (!m_transport.m_isConnected)
- m_sendQueue.push_back(wire);
- else
- m_socket.async_send(boost::asio::buffer(wire.wire(), wire.size()),
- bind(&impl::handle_async_send, this, _1, wire));
+ BlockSequence sequence;
+ sequence.push_back(wire);
+ m_transmissionQueue.push_back(sequence);
+
+ if (m_transport.m_isConnected && m_transmissionQueue.size() == 1) {
+ boost::asio::async_write(m_socket, *m_transmissionQueue.begin(),
+ bind(&Impl::handleAsyncWrite, this, _1,
+ m_transmissionQueue.begin()));
+ }
+
+ // if not connected or there is transmission in progress (m_transmissionQueue.size() > 1),
+ // next write will be scheduled either in connectHandler or in asyncWriteHandler
}
void
send(const Block& header, const Block& payload)
{
- if (!m_transport.m_isConnected)
- {
- m_sendPairQueue.push_back(std::make_pair(header, payload));
- }
- else
- {
- std::vector<boost::asio::const_buffer> buffers;
- buffers.reserve(2);
- buffers.push_back(boost::asio::buffer(header.wire(), header.size()));
- buffers.push_back(boost::asio::buffer(payload.wire(), payload.size()));
+ BlockSequence sequence;
+ sequence.push_back(header);
+ sequence.push_back(payload);
+ m_transmissionQueue.push_back(sequence);
- m_socket.async_send(buffers,
- bind(&impl::handle_async_send2, this, _1, header, payload));
- }
+ if (m_transport.m_isConnected && m_transmissionQueue.size() == 1) {
+ boost::asio::async_write(m_socket, *m_transmissionQueue.begin(),
+ bind(&Impl::handleAsyncWrite, this, _1,
+ m_transmissionQueue.begin()));
+ }
+
+ // if not connected or there is transmission in progress (m_transmissionQueue.size() > 1),
+ // next write will be scheduled either in connectHandler or in asyncWriteHandler
}
- inline bool
- processAll(uint8_t* buffer, size_t& offset, size_t availableSize)
+ void
+ handleAsyncWrite(const boost::system::error_code& error,
+ TransmissionQueue::iterator queueItem)
{
- Block element;
- while(offset < availableSize)
+ if (error)
{
- bool ok = Block::fromBuffer(buffer + offset, availableSize - offset, element);
+ if (error == boost::system::errc::operation_canceled) {
+ // async receive has been explicitly cancelled (e.g., socket close)
+ return;
+ }
+
+ m_transport.close();
+ throw Transport::Error(error, "error while sending data to socket");
+ }
+
+ m_transmissionQueue.erase(queueItem);
+
+ if (!m_transmissionQueue.empty()) {
+ boost::asio::async_write(m_socket, *m_transmissionQueue.begin(),
+ bind(&Impl::handleAsyncWrite, this, _1,
+ m_transmissionQueue.begin()));
+ }
+ }
+
+ bool
+ processAll(uint8_t* buffer, size_t& offset, size_t nBytesAvailable)
+ {
+ while (offset < nBytesAvailable)
+ {
+ Block element;
+ bool ok = Block::fromBuffer(buffer + offset, nBytesAvailable - offset, element);
if (!ok)
return false;
@@ -202,7 +218,7 @@
}
void
- handle_async_receive(const boost::system::error_code& error, std::size_t bytes_recvd)
+ handleAsyncReceive(const boost::system::error_code& error, std::size_t nBytesRecvd)
{
if (error)
{
@@ -215,12 +231,12 @@
throw Transport::Error(error, "error while receiving data from socket");
}
- m_inputBufferSize += bytes_recvd;
+ m_inputBufferSize += nBytesRecvd;
// do magic
std::size_t offset = 0;
- bool ok = processAll(m_inputBuffer, offset, m_inputBufferSize);
- if (!ok && m_inputBufferSize == MAX_LENGTH && offset == 0)
+ bool hasProcessedSome = processAll(m_inputBuffer, offset, m_inputBufferSize);
+ if (!hasProcessedSome && m_inputBufferSize == MAX_NDN_PACKET_SIZE && offset == 0)
{
m_transport.close();
throw Transport::Error(boost::system::error_code(),
@@ -242,32 +258,18 @@
}
m_socket.async_receive(boost::asio::buffer(m_inputBuffer + m_inputBufferSize,
- MAX_LENGTH - m_inputBufferSize), 0,
- bind(&impl::handle_async_receive, this, _1, _2));
- }
-
- void
- handle_async_send(const boost::system::error_code& error, const Block& wire)
- {
- // pass (needed to keep data block alive during the send)
- }
-
- void
- handle_async_send2(const boost::system::error_code& error,
- const Block& header, const Block& payload)
- {
- // pass (needed to keep data blocks alive during the send)
+ MAX_NDN_PACKET_SIZE - m_inputBufferSize), 0,
+ bind(&Impl::handleAsyncReceive, this, _1, _2));
}
protected:
- base_transport& m_transport;
+ BaseTransport& m_transport;
- typename protocol::socket m_socket;
- uint8_t m_inputBuffer[MAX_LENGTH];
+ typename Protocol::socket m_socket;
+ uint8_t m_inputBuffer[MAX_NDN_PACKET_SIZE];
size_t m_inputBufferSize;
- std::list< Block > m_sendQueue;
- std::list< std::pair<Block, Block> > m_sendPairQueue;
+ TransmissionQueue m_transmissionQueue;
bool m_connectionInProgress;
boost::asio::deadline_timer m_connectTimer;
@@ -278,19 +280,17 @@
class StreamTransportWithResolverImpl : public StreamTransportImpl<BaseTransport, Protocol>
{
public:
- typedef BaseTransport base_transport;
- typedef Protocol protocol;
- typedef StreamTransportWithResolverImpl<BaseTransport,Protocol> impl;
+ typedef StreamTransportWithResolverImpl<BaseTransport,Protocol> Impl;
- StreamTransportWithResolverImpl(base_transport& transport, boost::asio::io_service& ioService)
- : StreamTransportImpl<base_transport, protocol>(transport, ioService)
+ StreamTransportWithResolverImpl(BaseTransport& transport, boost::asio::io_service& ioService)
+ : StreamTransportImpl<BaseTransport, Protocol>(transport, ioService)
{
}
void
resolveHandler(const boost::system::error_code& error,
- typename protocol::resolver::iterator endpoint,
- const shared_ptr<typename protocol::resolver>&)
+ typename Protocol::resolver::iterator endpoint,
+ const shared_ptr<typename Protocol::resolver>&)
{
if (error)
{
@@ -300,7 +300,7 @@
throw Transport::Error(error, "Error during resolution of host or port");
}
- typename protocol::resolver::iterator end;
+ typename Protocol::resolver::iterator end;
if (endpoint == end)
{
this->m_transport.close();
@@ -308,25 +308,25 @@
}
this->m_socket.async_connect(*endpoint,
- bind(&impl::connectHandler, this, _1));
+ bind(&Impl::connectHandler, this, _1));
}
void
- connect(const typename protocol::resolver::query& query)
+ connect(const typename Protocol::resolver::query& query)
{
if (!this->m_connectionInProgress) {
this->m_connectionInProgress = true;
- // Wait at most 4 time::seconds to connect
+ // Wait at most 4 seconds to connect
/// @todo Decide whether this number should be configurable
this->m_connectTimer.expires_from_now(boost::posix_time::seconds(4));
- this->m_connectTimer.async_wait(bind(&impl::connectTimeoutHandler, this, _1));
+ this->m_connectTimer.async_wait(bind(&Impl::connectTimeoutHandler, this, _1));
- // typename boost::asio::ip::basic_resolver< protocol > resolver;
- shared_ptr<typename protocol::resolver> resolver =
- make_shared<typename protocol::resolver>(ref(this->m_socket.get_io_service()));
+ // typename boost::asio::ip::basic_resolver< Protocol > resolver;
+ shared_ptr<typename Protocol::resolver> resolver =
+ make_shared<typename Protocol::resolver>(ref(this->m_socket.get_io_service()));
- resolver->async_resolve(query, bind(&impl::resolveHandler, this, _1, _2, resolver));
+ resolver->async_resolve(query, bind(&Impl::resolveHandler, this, _1, _2, resolver));
}
}
};
diff --git a/src/transport/tcp-transport.cpp b/src/transport/tcp-transport.cpp
index 6fab8e0..7ffe530 100644
--- a/src/transport/tcp-transport.cpp
+++ b/src/transport/tcp-transport.cpp
@@ -53,18 +53,21 @@
void
TcpTransport::send(const Block& wire)
{
+ BOOST_ASSERT(static_cast<bool>(m_impl));
m_impl->send(wire);
}
void
TcpTransport::send(const Block& header, const Block& payload)
{
+ BOOST_ASSERT(static_cast<bool>(m_impl));
m_impl->send(header, payload);
}
void
TcpTransport::close()
{
+ BOOST_ASSERT(static_cast<bool>(m_impl));
m_impl->close();
m_impl.reset();
}
@@ -72,12 +75,15 @@
void
TcpTransport::pause()
{
- m_impl->pause();
+ if (static_cast<bool>(m_impl)) {
+ m_impl->pause();
+ }
}
void
TcpTransport::resume()
{
+ BOOST_ASSERT(static_cast<bool>(m_impl));
m_impl->resume();
}
diff --git a/src/transport/unix-transport.cpp b/src/transport/unix-transport.cpp
index cbfada8..03ee8b6 100644
--- a/src/transport/unix-transport.cpp
+++ b/src/transport/unix-transport.cpp
@@ -117,8 +117,9 @@
void
UnixTransport::pause()
{
- BOOST_ASSERT(static_cast<bool>(m_impl));
- m_impl->pause();
+ if (static_cast<bool>(m_impl)) {
+ m_impl->pause();
+ }
}
void
diff --git a/src/util/command-interest-generator.hpp b/src/util/command-interest-generator.hpp
index 8f97b7b..651a19b 100644
--- a/src/util/command-interest-generator.hpp
+++ b/src/util/command-interest-generator.hpp
@@ -32,6 +32,9 @@
/**
* @brief Helper class to generate CommandInterests
*
+ * @deprecated Use SignedInterest (generated by KeyChain) instead.
+ * See KeyChain::sign and KeyChain::signByIdentity methods.
+ *
* @see http://redmine.named-data.net/projects/nfd/wiki/Command_Interests
*/
class CommandInterestGenerator
diff --git a/src/util/command-interest-validator.hpp b/src/util/command-interest-validator.hpp
index 7d179a0..d132231 100644
--- a/src/util/command-interest-validator.hpp
+++ b/src/util/command-interest-validator.hpp
@@ -30,6 +30,15 @@
namespace ndn {
+/**
+ * @brief Helper class to validate CommandInterests
+ *
+ * @deprecated Use ValidatorConfig instead.
+ * See http://redmine.named-data.net/projects/ndn-cxx/wiki/CommandValidatorConf
+ * for more details about the configuration format of ValidatorConfig.
+ *
+ * @see http://redmine.named-data.net/projects/nfd/wiki/Command_Interests
+ */
class CommandInterestValidator : public Validator
{
public:
diff --git a/tests/integrated/test-faces.cpp b/tests/integrated/test-faces.cpp
index c86cd62..e7ce988 100644
--- a/tests/integrated/test-faces.cpp
+++ b/tests/integrated/test-faces.cpp
@@ -21,6 +21,7 @@
#include "face.hpp"
#include "util/scheduler.hpp"
+#include "security/key-chain.hpp"
#include "boost-test.hpp"
@@ -136,6 +137,20 @@
bind(&FacesFixture::onData, this),
bind(&FacesFixture::onTimeout, this));
+ Name veryLongName;
+ for (size_t i = 0; i <= MAX_NDN_PACKET_SIZE / 10; i++)
+ {
+ veryLongName.append("0123456789");
+ }
+
+ BOOST_CHECK_THROW(face.expressInterest(veryLongName, OnData(), OnTimeout()), Face::Error);
+
+ shared_ptr<Data> data = make_shared<Data>(veryLongName);
+ data->setContent(reinterpret_cast<const uint8_t*>("01234567890"), 10);
+ KeyChain keyChain;
+ keyChain.sign(*data);
+ BOOST_CHECK_THROW(face.put(*data), Face::Error);
+
BOOST_REQUIRE_NO_THROW(face.processEvents());
BOOST_CHECK_EQUAL(nData, 1);
diff --git a/tests/unit-tests/management/test-nfd-control-command.cpp b/tests/unit-tests/management/test-nfd-control-command.cpp
index 78b2877..045cd68 100644
--- a/tests/unit-tests/management/test-nfd-control-command.cpp
+++ b/tests/unit-tests/management/test-nfd-control-command.cpp
@@ -225,8 +225,7 @@
BOOST_CHECK_EQUAL(p1.getCost(), 0);
BOOST_REQUIRE(p1.hasFlags());
BOOST_CHECK_EQUAL(p1.getFlags(), static_cast<uint64_t>(ROUTE_FLAG_CHILD_INHERIT));
- BOOST_REQUIRE(p1.hasExpirationPeriod());
- BOOST_CHECK_GT(p1.getExpirationPeriod(), time::hours(240));
+ BOOST_CHECK_EQUAL(p1.hasExpirationPeriod(), false);
ControlParameters p2;
p2.setName("ndn:/example")
@@ -234,7 +233,7 @@
.setCost(6);
BOOST_CHECK_NO_THROW(command.validateRequest(p2));
command.applyDefaultsToRequest(p2);
- BOOST_CHECK_EQUAL(p2.getExpirationPeriod(), time::hours(1));
+ BOOST_CHECK_EQUAL(p2.hasExpirationPeriod(), false);
BOOST_CHECK_NO_THROW(command.validateResponse(p2));
}
diff --git a/tests/unit-tests/management/test-nfd-face-status.cpp b/tests/unit-tests/management/test-nfd-face-status.cpp
index 2691645..22c7264 100644
--- a/tests/unit-tests/management/test-nfd-face-status.cpp
+++ b/tests/unit-tests/management/test-nfd-face-status.cpp
@@ -39,7 +39,9 @@
.setNInInterests(10)
.setNInDatas(200)
.setNOutInterests(3000)
- .setNOutDatas(4);
+ .setNOutDatas(4)
+ .setNInBytes(1329719163)
+ .setNOutBytes(999110448);
Block wire;
BOOST_REQUIRE_NO_THROW(wire = status1.wireEncode());
@@ -50,15 +52,16 @@
// printf("0x%02x, ", *it);
// }
static const uint8_t expected[] = {
- 0x80, 0x46, 0x69, 0x01, 0x64, 0x72, 0x15, 0x74, 0x63, 0x70, 0x34, 0x3a,
+ 0x80, 0x52, 0x69, 0x01, 0x64, 0x72, 0x15, 0x74, 0x63, 0x70, 0x34, 0x3a,
0x2f, 0x2f, 0x31, 0x39, 0x32, 0x2e, 0x30, 0x2e, 0x32, 0x2e, 0x31, 0x3a,
0x36, 0x33, 0x36, 0x33, 0x81, 0x16, 0x74, 0x63, 0x70, 0x34, 0x3a, 0x2f,
0x2f, 0x31, 0x39, 0x32, 0x2e, 0x30, 0x2e, 0x32, 0x2e, 0x32, 0x3a, 0x35,
0x35, 0x35, 0x35, 0x35, 0x6d, 0x02, 0x27, 0x10, 0xc2, 0x01, 0x02, 0x90,
- 0x01, 0x0a, 0x91, 0x01, 0xc8, 0x92, 0x02, 0x0b, 0xb8, 0x93, 0x01, 0x04
+ 0x01, 0x0a, 0x91, 0x01, 0xc8, 0x92, 0x02, 0x0b, 0xb8, 0x93, 0x01, 0x04,
+ 0x94, 0x04, 0x4f, 0x41, 0xe7, 0x7b, 0x95, 0x04, 0x3b, 0x8d, 0x37, 0x30
};
- BOOST_REQUIRE_EQUAL_COLLECTIONS(expected, expected + sizeof(expected),
- wire.begin(), wire.end());
+ BOOST_CHECK_EQUAL_COLLECTIONS(expected, expected + sizeof(expected),
+ wire.begin(), wire.end());
BOOST_REQUIRE_NO_THROW(FaceStatus(wire));
FaceStatus status2(wire);
@@ -70,15 +73,20 @@
BOOST_CHECK_EQUAL(status1.getNInDatas(), status2.getNInDatas());
BOOST_CHECK_EQUAL(status1.getNOutInterests(), status2.getNOutInterests());
BOOST_CHECK_EQUAL(status1.getNOutDatas(), status2.getNOutDatas());
+ BOOST_CHECK_EQUAL(status1.getNInBytes(), status2.getNInBytes());
+ BOOST_CHECK_EQUAL(status1.getNOutBytes(), status2.getNOutBytes());
std::ostringstream os;
os << status2;
- BOOST_CHECK_EQUAL(os.str(), "FaceStatus(FaceID: 100, "
- "RemoteUri: tcp4://192.0.2.1:6363, "
- "LocalUri: tcp4://192.0.2.2:55555, "
- "ExpirationPeriod: 10000 milliseconds, "
- "Flags: 2, "
- "Counters: 10|200|3000|4)");
+ BOOST_CHECK_EQUAL(os.str(), "FaceStatus(FaceID: 100,\n"
+ "RemoteUri: tcp4://192.0.2.1:6363,\n"
+ "LocalUri: tcp4://192.0.2.2:55555,\n"
+ "ExpirationPeriod: 10000 milliseconds,\n"
+ "Flags: 2,\n"
+ "Counters: { Interests: {in: 10, out: 3000},\n"
+ " Data: {in: 200, out: 4},\n"
+ " bytes: {in: 1329719163, out: 999110448} }\n"
+ ")");
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/unit-tests/management/test-nfd-rib-entry.cpp b/tests/unit-tests/management/test-nfd-rib-entry.cpp
new file mode 100644
index 0000000..858598f
--- /dev/null
+++ b/tests/unit-tests/management/test-nfd-rib-entry.cpp
@@ -0,0 +1,341 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library 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 Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "management/nfd-rib-entry.hpp"
+#include "management/nfd-control-command.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+namespace nfd {
+
+BOOST_AUTO_TEST_SUITE(ManagementTestNfdRibEntry)
+
+const uint8_t RouteData[] =
+{
+ 0x81, 0x10, 0x69, 0x01, 0x01, 0x6f, 0x01, 0x80, 0x6a, 0x01, 0x64, 0x6c, 0x01, 0x02,
+ 0x6d, 0x02, 0x27, 0x10
+};
+
+const uint8_t RouteInfiniteExpirationPeriod[] =
+{
+ 0x81, 0x0C, 0x69, 0x01, 0x01, 0x6f, 0x01, 0x80, 0x6a, 0x01, 0x64, 0x6c, 0x01, 0x02
+};
+
+const uint8_t RibEntryData[] =
+{
+ // Header + Name
+ 0x80, 0x34, 0x07, 0x0e, 0x08, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f,
+ 0x08, 0x05, 0x77, 0x6f, 0x72, 0x6c, 0x64,
+ // Route
+ 0x81, 0x10, 0x69, 0x01, 0x01, 0x6f, 0x01, 0x80, 0x6a, 0x01, 0x64, 0x6c, 0x01, 0x02,
+ 0x6d, 0x02, 0x27, 0x10,
+ // Route
+ 0x81, 0x10, 0x69, 0x01, 0x02, 0x6f, 0x01, 0x00, 0x6a, 0x01, 0x20, 0x6c, 0x01, 0x01,
+ 0x6d, 0x02, 0x13, 0x88
+};
+
+const uint8_t RibEntryInfiniteExpirationPeriod[] =
+{
+ // Header + Name
+ 0x80, 0x30, 0x07, 0x0e, 0x08, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f,
+ 0x08, 0x05, 0x77, 0x6f, 0x72, 0x6c, 0x64,
+ // Route
+ 0x81, 0x10, 0x69, 0x01, 0x01, 0x6f, 0x01, 0x80, 0x6a, 0x01, 0x64, 0x6c, 0x01, 0x02,
+ 0x6d, 0x02, 0x27, 0x10,
+ // Route with no ExpirationPeriod
+ 0x81, 0x0C, 0x69, 0x01, 0x02, 0x6f, 0x01, 0x00, 0x6a, 0x01, 0x20, 0x6c, 0x01, 0x01,
+};
+
+BOOST_AUTO_TEST_CASE(RouteEncode)
+{
+ Route route;
+ route.setFaceId(1);
+ route.setOrigin(128);
+ route.setCost(100);
+ route.setFlags(ndn::nfd::ROUTE_FLAG_CAPTURE);
+ route.setExpirationPeriod(time::milliseconds(10000));
+
+ const Block& wire = route.wireEncode();
+
+ BOOST_REQUIRE_EQUAL_COLLECTIONS(RouteData,
+ RouteData + sizeof(RouteData),
+ wire.begin(), wire.end());
+}
+
+BOOST_AUTO_TEST_CASE(RouteDecode)
+{
+ Route route;
+
+ BOOST_REQUIRE_NO_THROW(route.wireDecode(Block(RouteData, sizeof(RouteData))));
+
+ BOOST_REQUIRE_EQUAL(route.getFaceId(), 1);
+ BOOST_REQUIRE_EQUAL(route.getOrigin(), 128);
+ BOOST_REQUIRE_EQUAL(route.getCost(), 100);
+ BOOST_REQUIRE_EQUAL(route.getFlags(), static_cast<uint64_t>(ndn::nfd::ROUTE_FLAG_CAPTURE));
+ BOOST_REQUIRE_EQUAL(route.getExpirationPeriod(), time::milliseconds(10000));
+ BOOST_REQUIRE_EQUAL(route.hasInfiniteExpirationPeriod(), false);
+}
+
+BOOST_AUTO_TEST_CASE(RouteInfiniteExpirationPeriodEncode)
+{
+ Route route;
+ route.setFaceId(1);
+ route.setOrigin(128);
+ route.setCost(100);
+ route.setFlags(ndn::nfd::ROUTE_FLAG_CAPTURE);
+ route.setExpirationPeriod(Route::INFINITE_EXPIRATION_PERIOD);
+
+ const Block& wire = route.wireEncode();
+
+ BOOST_REQUIRE_EQUAL_COLLECTIONS(RouteInfiniteExpirationPeriod,
+ RouteInfiniteExpirationPeriod + sizeof(RouteInfiniteExpirationPeriod),
+ wire.begin(), wire.end());
+}
+
+BOOST_AUTO_TEST_CASE(RouteInfiniteExpirationPeriodDecode)
+{
+ Route route;
+
+ BOOST_REQUIRE_NO_THROW(route.wireDecode(Block(RouteInfiniteExpirationPeriod,
+ sizeof(RouteInfiniteExpirationPeriod))));
+
+ BOOST_REQUIRE_EQUAL(route.getFaceId(), 1);
+ BOOST_REQUIRE_EQUAL(route.getOrigin(), 128);
+ BOOST_REQUIRE_EQUAL(route.getCost(), 100);
+ BOOST_REQUIRE_EQUAL(route.getFlags(), static_cast<uint64_t>(ndn::nfd::ROUTE_FLAG_CAPTURE));
+ BOOST_REQUIRE_EQUAL(route.getExpirationPeriod(), Route::INFINITE_EXPIRATION_PERIOD);
+ BOOST_REQUIRE_EQUAL(route.hasInfiniteExpirationPeriod(), true);
+}
+
+BOOST_AUTO_TEST_CASE(RouteOutputStream)
+{
+ Route route;
+ route.setFaceId(1);
+ route.setOrigin(128);
+ route.setCost(100);
+ route.setFlags(ndn::nfd::ROUTE_FLAG_CAPTURE);
+ route.setExpirationPeriod(time::milliseconds(10000));
+
+ std::ostringstream os;
+ os << route;
+
+ BOOST_CHECK_EQUAL(os.str(), "Route(FaceId: 1, Origin: 128, Cost: 100, "
+ "Flags: 2, ExpirationPeriod: 10000 milliseconds)");
+}
+
+BOOST_AUTO_TEST_CASE(RibEntryEncode)
+{
+ RibEntry entry;
+ entry.setName("/hello/world");
+
+ Route route1;
+ route1.setFaceId(1);
+ route1.setOrigin(128);
+ route1.setCost(100);
+ route1.setFlags(ndn::nfd::ROUTE_FLAG_CAPTURE);
+ route1.setExpirationPeriod(time::milliseconds(10000));
+ entry.addRoute(route1);
+
+ Route route2;
+ route2.setFaceId(2);
+ route2.setOrigin(0);
+ route2.setCost(32);
+ route2.setFlags(ndn::nfd::ROUTE_FLAG_CHILD_INHERIT);
+ route2.setExpirationPeriod(time::milliseconds(5000));
+ entry.addRoute(route2);
+
+ const Block& wire = entry.wireEncode();
+
+ BOOST_CHECK_EQUAL_COLLECTIONS(RibEntryData,
+ RibEntryData + sizeof(RibEntryData),
+ wire.begin(), wire.end());
+}
+
+BOOST_AUTO_TEST_CASE(RibEntryDecode)
+{
+ RibEntry entry;
+ BOOST_REQUIRE_NO_THROW(entry.wireDecode(Block(RibEntryData,
+ sizeof(RibEntryData))));
+
+ BOOST_CHECK_EQUAL(entry.getName(), "/hello/world");
+ BOOST_CHECK_EQUAL(entry.getRoutes().size(), 2);
+
+ std::list<Route> routes = entry.getRoutes();
+
+ std::list<Route>::const_iterator it = routes.begin();
+ BOOST_CHECK_EQUAL(it->getFaceId(), 1);
+ BOOST_CHECK_EQUAL(it->getOrigin(), 128);
+ BOOST_CHECK_EQUAL(it->getCost(), 100);
+ BOOST_CHECK_EQUAL(it->getFlags(), static_cast<uint64_t>(ndn::nfd::ROUTE_FLAG_CAPTURE));
+ BOOST_CHECK_EQUAL(it->getExpirationPeriod(), time::milliseconds(10000));
+ BOOST_CHECK_EQUAL(it->hasInfiniteExpirationPeriod(), false);
+
+ ++it;
+ BOOST_CHECK_EQUAL(it->getFaceId(), 2);
+ BOOST_CHECK_EQUAL(it->getOrigin(), 0);
+ BOOST_CHECK_EQUAL(it->getCost(), 32);
+ BOOST_CHECK_EQUAL(it->getFlags(), static_cast<uint64_t>(ndn::nfd::ROUTE_FLAG_CHILD_INHERIT));
+ BOOST_CHECK_EQUAL(it->getExpirationPeriod(), time::milliseconds(5000));
+ BOOST_CHECK_EQUAL(it->hasInfiniteExpirationPeriod(), false);
+}
+
+BOOST_AUTO_TEST_CASE(RibEntryInfiniteExpirationPeriodEncode)
+{
+ RibEntry entry;
+ entry.setName("/hello/world");
+
+ Route route1;
+ route1.setFaceId(1);
+ route1.setOrigin(128);
+ route1.setCost(100);
+ route1.setFlags(ndn::nfd::ROUTE_FLAG_CAPTURE);
+ route1.setExpirationPeriod(time::milliseconds(10000));
+ entry.addRoute(route1);
+
+ Route route2;
+ route2.setFaceId(2);
+ route2.setOrigin(0);
+ route2.setCost(32);
+ route2.setFlags(ndn::nfd::ROUTE_FLAG_CHILD_INHERIT);
+ route2.setExpirationPeriod(Route::INFINITE_EXPIRATION_PERIOD);
+ entry.addRoute(route2);
+
+ const Block& wire = entry.wireEncode();
+
+ BOOST_CHECK_EQUAL_COLLECTIONS(RibEntryInfiniteExpirationPeriod,
+ RibEntryInfiniteExpirationPeriod +
+ sizeof(RibEntryInfiniteExpirationPeriod),
+ wire.begin(), wire.end());
+}
+
+BOOST_AUTO_TEST_CASE(RibEntryInfiniteExpirationPeriodDecode)
+{
+ RibEntry entry;
+ BOOST_REQUIRE_NO_THROW(entry.wireDecode(Block(RibEntryInfiniteExpirationPeriod,
+ sizeof(RibEntryInfiniteExpirationPeriod))));
+
+ BOOST_CHECK_EQUAL(entry.getName(), "/hello/world");
+ BOOST_CHECK_EQUAL(entry.getRoutes().size(), 2);
+
+ std::list<Route> routes = entry.getRoutes();
+
+ std::list<Route>::const_iterator it = routes.begin();
+ BOOST_CHECK_EQUAL(it->getFaceId(), 1);
+ BOOST_CHECK_EQUAL(it->getOrigin(), 128);
+ BOOST_CHECK_EQUAL(it->getCost(), 100);
+ BOOST_CHECK_EQUAL(it->getFlags(), static_cast<uint64_t>(ndn::nfd::ROUTE_FLAG_CAPTURE));
+ BOOST_CHECK_EQUAL(it->getExpirationPeriod(), time::milliseconds(10000));
+ BOOST_CHECK_EQUAL(it->hasInfiniteExpirationPeriod(), false);
+
+ ++it;
+ BOOST_CHECK_EQUAL(it->getFaceId(), 2);
+ BOOST_CHECK_EQUAL(it->getOrigin(), 0);
+ BOOST_CHECK_EQUAL(it->getCost(), 32);
+ BOOST_CHECK_EQUAL(it->getFlags(), static_cast<uint64_t>(ndn::nfd::ROUTE_FLAG_CHILD_INHERIT));
+ BOOST_CHECK_EQUAL(it->getExpirationPeriod(), Route::INFINITE_EXPIRATION_PERIOD);
+ BOOST_CHECK_EQUAL(it->hasInfiniteExpirationPeriod(), true);
+}
+
+BOOST_AUTO_TEST_CASE(RibEntryClear)
+{
+ RibEntry entry;
+ entry.setName("/hello/world");
+
+ Route route1;
+ route1.setFaceId(1);
+ route1.setOrigin(128);
+ route1.setCost(100);
+ route1.setFlags(ndn::nfd::ROUTE_FLAG_CAPTURE);
+ route1.setExpirationPeriod(time::milliseconds(10000));
+ entry.addRoute(route1);
+ BOOST_REQUIRE_EQUAL(entry.getRoutes().size(), 1);
+
+ std::list<Route> routes = entry.getRoutes();
+
+ std::list<Route>::const_iterator it = routes.begin();
+ BOOST_CHECK_EQUAL(it->getFaceId(), 1);
+ BOOST_CHECK_EQUAL(it->getOrigin(), 128);
+ BOOST_CHECK_EQUAL(it->getCost(), 100);
+ BOOST_CHECK_EQUAL(it->getFlags(), static_cast<uint64_t>(ndn::nfd::ROUTE_FLAG_CAPTURE));
+ BOOST_CHECK_EQUAL(it->getExpirationPeriod(), time::milliseconds(10000));
+ BOOST_CHECK_EQUAL(it->hasInfiniteExpirationPeriod(), false);
+
+ entry.clearRoutes();
+ BOOST_CHECK_EQUAL(entry.getRoutes().size(), 0);
+
+ Route route2;
+ route2.setFaceId(2);
+ route2.setOrigin(0);
+ route2.setCost(32);
+ route2.setFlags(ndn::nfd::ROUTE_FLAG_CHILD_INHERIT);
+ route2.setExpirationPeriod(Route::INFINITE_EXPIRATION_PERIOD);
+ entry.addRoute(route2);
+ BOOST_REQUIRE_EQUAL(entry.getRoutes().size(), 1);
+
+ routes = entry.getRoutes();
+
+ it = routes.begin();
+ BOOST_CHECK_EQUAL(it->getFaceId(), 2);
+ BOOST_CHECK_EQUAL(it->getOrigin(), 0);
+ BOOST_CHECK_EQUAL(it->getCost(), 32);
+ BOOST_CHECK_EQUAL(it->getFlags(), static_cast<uint64_t>(ndn::nfd::ROUTE_FLAG_CHILD_INHERIT));
+ BOOST_CHECK_EQUAL(it->getExpirationPeriod(), Route::INFINITE_EXPIRATION_PERIOD);
+ BOOST_CHECK_EQUAL(it->hasInfiniteExpirationPeriod(), true);
+}
+
+BOOST_AUTO_TEST_CASE(RibEntryOutputStream)
+{
+ RibEntry entry;
+ entry.setName("/hello/world");
+
+ Route route1;
+ route1.setFaceId(1);
+ route1.setOrigin(128);
+ route1.setCost(100);
+ route1.setFlags(ndn::nfd::ROUTE_FLAG_CAPTURE);
+ route1.setExpirationPeriod(time::milliseconds(10000));
+ entry.addRoute(route1);
+
+ Route route2;
+ route2.setFaceId(2);
+ route2.setOrigin(0);
+ route2.setCost(32);
+ route2.setFlags(ndn::nfd::ROUTE_FLAG_CHILD_INHERIT);
+ route2.setExpirationPeriod(Route::INFINITE_EXPIRATION_PERIOD);
+ entry.addRoute(route2);
+
+ std::ostringstream os;
+ os << entry;
+
+ BOOST_CHECK_EQUAL(os.str(), "RibEntry{\n"
+ " Name: /hello/world\n"
+ " Route(FaceId: 1, Origin: 128, Cost: 100, "
+ "Flags: 2, ExpirationPeriod: 10000 milliseconds)\n"
+ " Route(FaceId: 2, Origin: 0, Cost: 32, "
+ "Flags: 1, ExpirationPeriod: Infinity)\n"
+ "}");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace nfd
+} // namespace ndn