Last active
October 11, 2015 15:34
-
-
Save yoursunny/22a7d53711b4e9bc198a to your computer and use it in GitHub Desktop.
NFD Face System design for LinkService http://redmine.named-data.net/issues/2222 and permanent face http://redmine.named-data.net/issues/2491
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
// Face design | |
// This design incorporates: | |
// Link Services http://redmine.named-data.net/issues/2222 | |
// Permanent Face http://redmine.named-data.net/issues/2491 | |
// -------- Face, Socket, LinkService -------- | |
namespace nfd { | |
namespace face { | |
typedef uint64_t FaceId; | |
enum class FaceState { | |
NONE, | |
UP, | |
DOWN, | |
CLOSED, | |
FAILED | |
}; | |
// More states such as UNAUTHENTICATED will be needed when we have tunnel authentication. | |
// By then, these existing states should be copied into a TransportState enum, | |
// and other states are created by LinkService. | |
class Face : noncopyable | |
{ | |
public: | |
Face(unique_ptr<LinkService> service, unique_ptr<Transport> transport); | |
public: // upper interface connected to forwarding | |
void | |
sendInterest(const Interest& interest); | |
void | |
sendData(const Data& interest); | |
void | |
sendNack(const Nack& interest); | |
Signal<LinkService, Interest>& afterReceiveInterest; | |
Signal<LinkService, Data>& afterReceiveData; | |
Signal<LinkService, Nack>& afterReceiveNack; | |
public: // static properties | |
FaceId | |
getId() const; // from Face | |
FaceUri | |
getLocalUri() const; // from Transport | |
FaceUri | |
getRemoteUri() const; // from Transport | |
FaceScope | |
getScope() const; // from Transport | |
FacePersistency | |
getPersistency() const; // from Transport | |
void | |
setPersistency(FacePersistency persistency); // from Transport | |
LinkType // point-to-point|multi-access | |
getLinkType() const; // from Transport | |
public: // dynamic properties | |
FaceState | |
getState() const; // from Transport | |
Signal<Transport, FaceState/*old*/, FaceState/*new*/>& afterStateChange; | |
// The 'fail' signal on old Face is equivalent to changing state to CLOSED or FAILED. | |
void | |
close(); // calls transport.close() | |
// For now, 'close' goes straight to Transport. When we have tunnel authentication, | |
// 'close' may need to be processed by LinkService before going into Transport, | |
// so that the authenticated session can be explicitly terminated. | |
FaceCounters | |
getCounters() const; // network layer packet counters from LinkService, link layer packet and byte counters from Transport | |
}; | |
class Transport | |
{ | |
public: | |
struct Packet | |
{ | |
Block packet; | |
NetworkAddress localAddr; | |
NetworkAddress remoteAddr; | |
} | |
public: // upper interface | |
void | |
close(); // invoke .doClose and change state to CLOSED | |
void | |
send(const Packet& packet); // increment counter and call .doSend | |
Signal<Transport, Packet> afterReceive; | |
public: // static properties | |
FaceUri | |
getLocalUri() const; | |
FaceUri | |
getRemoteUri() const; | |
FacePersistency | |
getPersistency() const; | |
// If persistency==PERMANENT, Transport is responsible for recovery. | |
// But tunnel authentication should be done by another component through a signal. | |
void | |
setPersistency(FacePersistency persistency); | |
LinkType | |
getLinkType() const; | |
public: // dynamic properties | |
FaceState | |
getState() const; | |
Signal<Transport, FaceState/*old*/, FaceState/*new*/> afterStateChange; | |
LinkCounters | |
getCounters() const; // link layer packet and byte counters | |
protected: // to be invoked by subclass | |
/** \brief receives a link-layer packet | |
*/ | |
void | |
receive(const Packet& packet); | |
void | |
setLocalUri(const FaceUri& uri); | |
void | |
setRemoteUri(const FaceUri& uri); | |
void | |
setScope(FaceScope scope); | |
void | |
setLinkType(LinkType linkType); | |
/** \brief change UP/DOWN state | |
*/ | |
void | |
changeState(FaceState newState); | |
// Initially a transport is UP. | |
// After a socket error, with persistency==PERMANENT, state becomes DOWN; after recovery, state becomes UP again. | |
// After a socket error, with persistency!=PERMANENT, state becomes FAILED. | |
// After .close is called, state becomes CLOSED. | |
private: // to be overridden by subclass | |
virtual void | |
beforeChangePersistency(FacePersistency newPersistency); | |
virtual void | |
doClose() = 0; // close underlying socket | |
virtual void | |
doSend(const Packet& packet) = 0; | |
}; | |
class LinkService | |
{ | |
public: | |
void | |
setTransport(Transport& transport); | |
public: // upper interface connected to forwarding | |
void | |
sendInterest(const Interest& interest); // increment counter and call .doSendInterest | |
void | |
sendData(const Data& interest); // increment counter and call .doSendData | |
void | |
sendNack(const Nack& interest); // increment counter and call .doSendNack | |
Signal<LinkService, Interest> afterReceiveInterest; | |
Signal<LinkService, Data> afterReceiveData; | |
Signal<LinkService, Nack> afterReceiveNack; | |
private: // upper interface to be overridden in subclass | |
virtual void | |
doSendInterest(const Interest& interest) = 0; | |
virtual void | |
doSendData(const Data& interest) = 0; | |
virtual void | |
doSendNack(const Nack& interest) = 0; | |
protected: // upper interface to be invoked in subclass | |
void | |
receiveInterest(const Interest& interest); // increment counter and signal afterReceiveInterest | |
void | |
receiveData(const Data& data); // increment counter and signal afterReceiveData | |
void | |
receiveNack(const Nack& nack); // increment counter and signal afterReceiveNack | |
protected: // lower interface to be invoked in subclass | |
bool | |
sendPacket(const Transport::Packet& packet); | |
private: // lower interface to be overridden in subclass | |
virtual void | |
receivePacket(const Transport::Packet& packet) = 0; | |
public: // dynamic properties | |
NetCounters | |
getCounters(); // network layer packet counters | |
}; | |
} // namespace face | |
} // namespace nfd | |
// -------- generic LinkService -------- | |
namespace nfd { | |
namespace face { | |
class GenericLinkService : public LinkService | |
{ | |
public: | |
class Options | |
{ | |
bool enableFragmentation; | |
bool enableReassembly; | |
// send path and receive path should have separate options if it makes sense | |
time::nanoseconds reassemblyTimeout; | |
// (other options can be added when necessary) | |
bool allowLocalFields; | |
// enableLocalFields enables encoding of IncomingFaceId, and decoding of NextHopFaceId and CachePolicy. | |
// Nack is always enabled, because there's no harm keeping it enabled. | |
// When decoding, implementation should ensure a field is attached on a correct network layer packet type, | |
// especially when protocol defines "packet MUST be dropped" (eg. Nack is only allowed on an Interest). | |
}; | |
explicit | |
GenericLinkService(const Options& options); | |
const Options& | |
getOptions() const; | |
void | |
setOptions(const Options& options); | |
private: // send path entrypoint | |
virtual void | |
doSendInterest(const Interest& interest) override; | |
virtual void | |
doSendData(const Data& interest) override; | |
virtual void | |
doSendNack(const Nack& interest) override; | |
private: // receive path entrypoint | |
virtual void | |
receivePacket(const Transport::Packet& packet) override; | |
}; | |
// Apart from packet encoding/decoding (which includes Nack, IncomingFaceId, NextHopFaceId, CachePolicy), | |
// we only have fragmentation+reassembly service for now. | |
// So we only need a few classes for fragmentation and reassembly (similar to NDNLPv1 implementation), | |
// plus a separate step for assigning sequence numbers. | |
// Unlike NDNLPv1 implementation, sequence number allocation should happen after fragmentation; | |
// which is necessary to accomodate transmitting IDLE packets from other services. | |
// Each of doSendX methods should do encoding, invoke fragmentation, invoke seq allocation, and invoke .sendPacket to pass down LpPacket; | |
// the latter 3 steps should be done in a common helper function; | |
// in case fragmentation is disabled, that helper function can invoke .sendPacket straight. | |
// receivePacket should call reassembly, do decoding, and invoke .receiveX to pass up network layer packet; | |
// in case reassembly is disabled, this method can skip reassembly step. | |
} // namespace face | |
} // namespace nfd |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment