Skip to content

Instantly share code, notes, and snippets.

@yoursunny
Last active August 29, 2015 14:22
Show Gist options
  • Save yoursunny/2c1ce576cd23c9b8b817 to your computer and use it in GitHub Desktop.
Save yoursunny/2c1ce576cd23c9b8b817 to your computer and use it in GitHub Desktop.
// # NDNLPv2 API: NACK in client Face
// ## extending ndn::Face class
namespace ndn {
typedef function<void(const Interest&, const Data&)> DataCallback;
typedef function<void(const Interest&, const lp::Nack&)> NackCallback;
typedef function<void(const Interest&)> TimeoutCallback;
// note: OnData and OnTimeout typedefs were mistakes, because type names should be a noun.
// Also, OnData shouldn't need a mutable reference for the Data.
// Therefore, this API is using a new set of callbacks.
partial class Face
{
public: // consumer
/** \brief sends an Interest
* \param interest the Interest; a copy will be made, so that the caller
* is not required to maintain the argument unchanged
* \param afterSatisfied a function to be invoked if a Data is returned
* \param afterNacked a function to be invoked if a Network NACK is returned
* \param afterTimeout a function to be invoked if neither Data nor Network NACK
* is returned within InterestLifetime
*/
const PendingInterestId*
expressInterest(const Interest& interest,
const DataCallback& afterSatisfied,
const NackCallback& afterNacked,
const TimeoutCallback& afterTimeout);
// note: I wanted to make the last two parameters optional, but it would cause compilation error
// because std::function<> template has aggresive constructor which takes everything,
// so that the compiler thinks an expressInterest call with two or three arguments
// is ambiguous with the deprecated form below.
// Declaring XCallback as plain function signatures instead of std::function helps,
// but that would reject std::bind arguments.
// Thus, this has to require five arguments for now.
// After the other form is removed, the last two arguments could default to nullptr.
/** \deprecated use expressInterest(Interest, DataCallback, NackCallback, TimeoutCallback)
*/
const PendingInterestId*
expressInterest(const Interest& interest,
const OnData& onData,
const OnTimeout& onTimeout = nullptr);
public: // producer
/** \brief sends a Network NACK
* \param nack the Nack; a copy will be made, so that the caller
* is not required to maintain the argument unchanged
*/
void
put(const lp::Nack& nack);
};
} // namespace ndn
// ## implementation detail: PendingInterest struct
/** \brief represents a pending Interest
* \note This type is implementation detail of Face class.
*
* The Face maintains a collection of PendingInterests.
* A PendingInterest is added when an Interest is expressed,
* and is removed when it's satisified by a Data packet,
* rejected by a Nack, or timed out.
*/
partial class PendingInterest
{
public:
PendingInterest(shared_ptr<const Interest> interest,
const DataCallback& dataCallback,
const NackCallback& nackCallback,
const TimeoutCallback& timeoutCallback,
Scheduler& scheduler);
/** \return the Interest
*/
shared_ptr<const Interest>
getInterest() const;
/** \brief invokes the DataCallback
* \note If the DataCallback is an empty function, this method does nothing.
*/
void
invokeDataCallback(const Data& data);
/** \brief invokes the NackCallback
* \note If the NackCallback is an empty function, this method does nothing.
*/
void
invokeNackCallback(const lp::Nack& nack);
private:
shared_ptr<const Interest> m_interest;
DataCallback m_dataCallback;
NackCallback m_nackCallback;
TimeoutCallback m_timeoutCallback;
};
// unchanged: setDeleter, invokeTimeoutCallback, m_timeoutEvent, m_deleter
// ## implementation detail: FaceImpl
partial class FaceImpl
{
public:
void
nackPendingInterests(const Nack& nack);
// note: The procedure is similar to satisfyPendingInterests.
void
asyncExpressInterest(shared_ptr<const Interest> interest,
const DataCallback& afterSatisfied,
const NackCallback& afterNacked,
const TimeoutCallback& afterTimeout);
void
asyncPutNack(shared_ptr<const Nack> nack);
// note: It's intentional to use shared_ptr<const Nack> instead of const shared_ptr<const Nack>& because that's semantically wrong.
};
// asyncExpressInterest, asyncPutData, asyncPutNack should construct lp::Packet from every network layer packet,
// and set LocalControlHeader fields into LpPacket.
// ## implementation detail: Face
// expressInterest is updated to call asyncExpressInterest with afterNacked argument.
/** \brief extract local fields from NDNLPv2 packet and tag onto a network layer packet
*/
template<typename NETPKT>
static void
extractLpLocalFields(NETPKT& netPacket, const lp::Packet& lpPacket);
// note: This extracts IncomingFaceId field and puts it into LocalControlHeader.
// Eventually LocalControlHeader will be deprecated and replaced with a Tag.
// This template requires Nack class to be extended with 'nfd::LocalControlHeader& getLocalControlHeader()' API,
// but the storage of this field can be redirected to the Interest contained within.
void
Face::onReceiveElement(const Block& blockFromDaemon)
{
lp::Packet lpPacket(blockFromDaemon); // bare Interest/Data is a valid lp::Packet, no need to distinguish
Block netPacket = /* extract Fragment as a Block */;
switch (netPacket.type()) {
case tlv::Interest:
shared_ptr<Interest> interest = /* parse netPacket as Interest */;
if (lpPacket.has<lp::NackField>()) {
auto nack = make_shared<lp::Nack>(std::move(*interest));
interest.reset();
extractLpLocalFields(*nack, lpPacket);
m_impl->nackPendingInterests(*nack);
}
else {
extractLpLocalFields(*interest, lpPacket);
/* incoming Interest processing */
}
break;
case tlv::Data:
shared_ptr<Data> data = /* parse netPacket as Data */;
extractLpLocalFields(*data, lpPacket);
/* incoming Data processing */
break;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment