Last active
August 29, 2015 14:22
-
-
Save yoursunny/2c1ce576cd23c9b8b817 to your computer and use it in GitHub Desktop.
NDNLPv2 client Face API http://redmine.named-data.net/issues/2883
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// # 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