Last active
March 9, 2016 22:16
-
-
Save yoursunny/e3c520a590af86a0bb37 to your computer and use it in GitHub Desktop.
NFD management dispatcher http://redmine.named-data.net/issues/2200
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
namespace ndn { | |
/** \brief represents a dispatcher on server side of NFD Management protocol | |
*/ | |
class ManagementDispatcher : noncopyable | |
{ | |
public: // constructor | |
ManagementDispatcher(Face& face, KeyChain& keyChain); | |
virtual | |
~ManagementDispatcher(); | |
public: // authorization | |
/** \brief a function to be called if authorization is successful | |
*/ | |
typedef std::function<void(const Name& identity)> AcceptContinuation; | |
enum RejectReply { | |
REJECT_REPLY_SILENT, | |
REJECT_REPLY_401, | |
REJECT_REPLY_NACK | |
}; | |
/** \brief a function to be called if authorization is rejected | |
*/ | |
typedef std::function<void(RejectReply)> RejectContinuation; | |
/** \brief a function that performs authorization | |
* \param prefix top-level prefix, eg. "/localhost/nfd"; | |
* This argument can be inspected to allow Interests only under a subset of | |
* top-level prefixes (eg. allow "/localhost/nfd" only), | |
* or to use different trust model regarding to the prefix. | |
* \param interest incoming Interest | |
* \param params parsed ControlParameters for ControlCommand, otherwise empty | |
* | |
* Either accept or reject must be called after authorization completes. | |
*/ | |
typedef std::function<void(const Name& prefix, const Interest& interest, | |
const ControlParameters& params, | |
AcceptContinuation accept, RejectContinuation reject)> Authorization; | |
/** \return an Authorization that accepts all Interests with empty identity | |
*/ | |
Authorization | |
makeAcceptAllAuthorization(); | |
public: // reply encryption and signing | |
/** \brief a function to process a reply Data | |
* | |
* This function may optionally encrypt the Data, | |
* and must sign the Data. | |
*/ | |
typedef std::function<void(const Name& prefix, const Interest& interest, const Name& identity, | |
shared_ptr<Data> data)> ReplyEncrypt; | |
/** \return a ReplyEncrypt that performs no encryption, | |
* but signs Data with this dispatcher's KeyChain | |
*/ | |
ReplyEncrypt | |
makeNullEncryption(); | |
public: // reply | |
/** \brief a function to be called to send reply Data | |
* \param data an unencrypted, unsigned Data | |
*/ | |
typedef std::function<void(shared_ptr<Data> data)> Reply; | |
/** \brief a function to be called when all replies have been sent | |
*/ | |
typedef std::function<void()> End; | |
public: // ControlCommand | |
/** \brief a function to handle an authorized ControlCommand | |
*/ | |
typedef std::function<void(const Name& prefix, const Interest& interest, | |
const Name& identity, const ControlParameters& params, | |
Reply reply)> ControlCommandHandler; | |
/** \brief register a ControlCommand | |
* \param relPrefix a prefix for this command, eg. "faces/create" | |
*/ | |
void | |
addControlCommand(const std::vector<name::Component>& relPrefix, | |
Authorization authorization, | |
ControlCommandHandler handler, | |
ReplyEncrypt replyEncrypt); | |
public: // StatusDataset | |
/** \brief a function to handle a StatusDataset request | |
* \param interest the request; its Name doesn't contain version and segment components | |
* \param identity Name() if dataset is public; otherwise the identity of requester | |
* | |
* This function can generate zero or more Data packets and pass them to \p reply, | |
* and must call \p end after all Data packets are sent. | |
*/ | |
typedef std::function<void(const Name& prefix, const Interest& interest, | |
const Name& identity, | |
Reply reply, End end)> StatusDatasetHandler; | |
/** \brief register a StatusDataset or a prefix under which StatusDatasets can be requested | |
* \param relPrefix a prefix for this dataset, eg. "faces/list" | |
* \param authorization should set identity to Name() if the dataset is public | |
*/ | |
void | |
addStatusDataset(const std::vector<name::Component>& relPrefix, | |
Authorization authorization, | |
StatusDatasetHandler handler, | |
ReplyEncrypt replyEncrypt); | |
public: // NotificationStream | |
/** \brief a function to post a notification | |
* \note caller doesn't need to maintain notification sequence numbers | |
*/ | |
typedef std::function<void(Block notification)> PostNotification; | |
/** \brief register a NotificationStream | |
* \param relPrefix a prefix for this notification stream, eg. "faces/events" | |
* \return a function into which notifications can be posted | |
*/ | |
PostNotification | |
addNotificationStream(const std::vector<name::Component>& relPrefix, | |
ReplyEncrypt replyEncrypt); | |
}; | |
} // namespace ndn | |
namespace nfd { | |
/** \brief a router face that is connected to InternalClientFace | |
*/ | |
class InternalFace : public nfd::Face | |
{ | |
}; | |
/** \brief a client face that is connected to NFD InternalFace | |
*/ | |
class InternalClientFace : public ndn::Face | |
{ | |
public: | |
/** \brief constructor a client face and hook to an InternalFace | |
*/ | |
explicit | |
ManagementFace(InternalFace& internalFace); | |
}; | |
} // namespace nfd | |
// example for FaceManager | |
namespace nfd { | |
class ManagementValidator | |
{ | |
public: | |
void | |
ManagementValidator(ConfigFile section); | |
void | |
validate(const Name& prefix, const Interest& interest, | |
const ControlParameters& params, | |
ManagementDispatcher::AcceptContinuation accept, | |
ManagementDispatcher::RejectContinuation reject) | |
{ | |
const Name& identity = interest.getKeyLocator().getName(); | |
auto it = m_privileges.find(identity); | |
if (it == m_privileges.end()) { | |
reject(REJECT_REPLY_401); | |
return; | |
} | |
name::Component module = interest.getName().at(prefix.size()); | |
if (it->second.count(module) > 0) { | |
accept(identity); | |
} | |
else { | |
reject(REJECT_REPLY_401); | |
} | |
} | |
private: | |
std::unordered_map<Name, std::unordered_set<name::Components>> m_privileges; // identity=>modules | |
}; | |
class FaceManager | |
{ | |
public: | |
void | |
dispatcherRegister(ManagementDispatcher& dispatcher) | |
{ | |
auto commandAuthorization = bind(&ManagementValidator::validate, m_validator, _1, _2, _3, _4); | |
auto acceptAllAuthorization = dispatcher.makeAcceptAllAuthorization(); | |
auto nullEncryption = dispatcher.makeNullEncryption(); | |
dispatcher.addControlCommand({"faces", "create"}, commandAuthorization, | |
bind(&FaceManager::handleCreateCommand, this, _1, _2, _3, _4, _5), | |
nullEncryption); | |
dispatcher.addStatusDataset({"faces", "list"}, acceptAllAuthorization, | |
bind(&FaceManager::handleListRequest, this, _1, _2, _3, _4, _5), | |
nullEncryption); | |
this->m_postStatusChangeNotification = dispatcher.addNotificationStream({"faces", "events", nullEncryption); | |
this->startNotificationStream(); | |
} | |
void | |
startNotificationStream() | |
{ | |
m_faceTable.onAdd += [] (shared_ptr<Face> face) { | |
FaceEvent evt = {CREATED, face}; | |
m_postStatusChangeNotification(evt.wireEncode()); | |
} | |
} | |
private: | |
void | |
handleCreateCommand(const Name& prefix, const Interest& interest, | |
const Name& identity, const ControlParameters& params, | |
ManagementDispatcher::Reply reply) | |
{ | |
createFace(params.faceUri, | |
[&] (FaceId faceId) { | |
auto response = make_shared<Data>(interest.getName()); | |
response->setContent(successMessage); | |
reply(response); | |
}, | |
[&] { | |
auto response = make_shared<Data>(interest.getName()); | |
response->setContent(errorMessage); | |
reply(response); | |
}); | |
} | |
void | |
handleListRequest(const Name& prefix, const Interest& interest, | |
const Name& identity, | |
Reply reply, End end) | |
{ | |
SegmentedStream ss; | |
ss.onSegmentComplete += reply; | |
for (Face face : m_faceTable) { | |
ss.append(face.getFaceStatus()) | |
} | |
ss.end(); | |
end(); | |
} | |
private: | |
FaceTable m_faceTable; | |
ManagementValidator m_validator; | |
ManagementDispatcher::PostNotification m_postStatusChangeNotification; | |
}; | |
} // namespace nfd |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment