blob: 32a19cd79703c0cd7b9ee7c3ef29a7633fdd52e9 [file] [log] [blame]
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
/**
* Copyright (C) 2013 Regents of the University of California.
* See COPYING for copyright and distribution information.
*/
#include "common.hpp"
#include "ndnd-controller.hpp"
#include "../face.hpp"
#include "../security/signature-sha256-with-rsa.hpp"
#include "../util/random.hpp"
#include "ndnd-forwarding-entry.hpp"
#include "ndnd-face-instance.hpp"
#include "ndnd-status-response.hpp"
namespace ndn {
namespace ndnd {
Controller::Controller(Face& face)
: m_face(face)
, m_faceId(-1)
{
}
void
Controller::selfRegisterPrefix(const Name& prefixToRegister,
const SuccessCallback& onSuccess,
const FailCallback& onFail)
{
if (!m_ndndId.hasValue())
{
if (m_filterRequests.empty())
{
m_face.expressInterest(Name("/%C1.M.S.localhost/%C1.M.SRV/ndnd/KEY"),
bind(&Controller::onNdnidFetched, this, _1, _2),
bind(onFail, "NDNDID fetching timed out"));
}
m_filterRequests.push_back(FilterRequest(prefixToRegister, onSuccess, onFail));
}
else
startPrefixAction(ForwardingEntry("selfreg", prefixToRegister),
bind(&Controller::recordSelfRegisteredFaceId, this, _1, onSuccess),
onFail);
}
void
Controller::selfDeregisterPrefix(const Name& prefixToRegister,
const SuccessCallback& onSuccess,
const FailCallback& onFail)
{
if (!m_ndndId.hasValue() || m_faceId == -1)
{
if (static_cast<bool>(onFail))
onFail("NDNID is not available (must have been present after a successful registration operation)");
return;
}
startPrefixAction(ForwardingEntry("unreg", prefixToRegister, m_faceId),
bind(onSuccess), onFail);
}
void
Controller::onNdnidFetched(const Interest& interest, Data& data)
{
if (data.getName().size() > interest.getName().size())
{
m_ndndId = data.getName()[interest.getName().size()];
if (m_ndndId.value_size() < 6)
{
for (FilterRequestList::iterator i = m_filterRequests.begin();
i != m_filterRequests.end();
++i)
{
if (static_cast<bool>(i->m_onFailure))
i->m_onFailure("Fetched unrecognized NDNID");
}
return;
}
for (FilterRequestList::iterator i = m_filterRequests.begin();
i != m_filterRequests.end();
++i)
{
startPrefixAction(ForwardingEntry("selfreg", i->m_prefixToRegister),
bind(&Controller::recordSelfRegisteredFaceId, this, _1, i->m_onSuccess),
i->m_onFailure);
}
}
else
{
for (FilterRequestList::iterator i = m_filterRequests.begin();
i != m_filterRequests.end();
++i)
{
if (static_cast<bool>(i->m_onFailure))
i->m_onFailure("NDNID cannot be fetched");
}
}
m_filterRequests.clear();
}
void
Controller::recordSelfRegisteredFaceId(const ForwardingEntry& entry,
const SuccessCallback& onSuccess)
{
m_faceId = entry.getFaceId();
if (static_cast<bool>(onSuccess))
onSuccess();
}
void
Controller::startFaceAction(const FaceInstance& entry,
const FaceOperationSucceedCallback& onSuccess,
const FailCallback& onFail)
{
// Set the ForwardingEntry as the content of a Data packet and sign.
Data data;
data.setName(Name().appendVersion(random::generateWord32()));
data.setContent(entry.wireEncode());
// Create an empty signature, since nobody going to verify it for now
// @todo In the future, we may require real signatures to do the registration
SignatureSha256WithRsa signature;
signature.setValue(Block(Tlv::SignatureValue));
data.setSignature(signature);
// Create an interest where the name has the encoded Data packet.
Name interestName;
interestName.append("ndnx");
interestName.append(m_ndndId.value_begin()+6, m_ndndId.value_end());
interestName.append(entry.getAction());
interestName.append(data.wireEncode());
Interest interest(interestName);
interest.setScope(1);
interest.setInterestLifetime(time::seconds(1));
interest.setMustBeFresh(true);
m_face.expressInterest(interest,
bind(&Controller::processFaceActionResponse, this, _2, onSuccess, onFail),
bind(onFail, "Command Interest failed"));
}
void
Controller::startPrefixAction(const ForwardingEntry& entry,
const PrefixOperationSucceedCallback& onSuccess,
const FailCallback& onFail)
{
// Set the ForwardingEntry as the content of a Data packet and sign.
Data data;
data.setName(Name().appendVersion(random::generateWord32()));
data.setContent(entry.wireEncode());
// Create an empty signature, since nobody going to verify it for now
// @todo In the future, we may require real signatures to do the registration
SignatureSha256WithRsa signature;
signature.setValue(Block(Tlv::SignatureValue));
data.setSignature(signature);
// Create an interest where the name has the encoded Data packet.
Name interestName;
interestName.append("ndnx");
interestName.append(m_ndndId.value_begin() + 6, m_ndndId.value_end());
interestName.append(entry.getAction());
interestName.append(data.wireEncode());
Interest interest(interestName);
interest.setScope(1);
interest.setInterestLifetime(time::seconds(1));
interest.setMustBeFresh(true);
m_face.expressInterest(interest,
bind(&Controller::processPrefixActionResponse, this, _2, onSuccess, onFail),
bind(onFail, "Command Interest timed out"));
}
void
Controller::processFaceActionResponse(Data& data,
const FaceOperationSucceedCallback& onSuccess,
const FailCallback& onFail)
{
Block content = data.getContent();
content.parse();
if (content.elements().empty())
{
if (static_cast<bool>(onFail))
onFail("Empty response");
return;
}
Block::element_const_iterator val = content.elements_begin();
switch (val->type())
{
case tlv::ndnd::FaceInstance:
{
FaceInstance entry;
entry.wireDecode(*val);
if (static_cast<bool>(onSuccess))
onSuccess(entry);
return;
}
case tlv::ndnd::StatusResponse:
{
StatusResponse resp;
resp.wireDecode(*val);
if (static_cast<bool>(onFail))
onFail(resp.getInfo());
return;
}
default:
{
if (static_cast<bool>(onFail))
onFail("Invalid response");
return;
}
}
}
void
Controller::processPrefixActionResponse(Data& data,
const PrefixOperationSucceedCallback& onSuccess,
const FailCallback& onFail)
{
Block content = data.getContent();
content.parse();
if (content.elements().empty())
{
if (static_cast<bool>(onFail))
onFail("Empty response");
return;
}
Block::element_const_iterator val = content.elements_begin();
switch (val->type())
{
case tlv::ndnd::ForwardingEntry:
{
ForwardingEntry entry;
entry.wireDecode(*val);
if (static_cast<bool>(onSuccess))
onSuccess(entry);
return;
}
case tlv::ndnd::StatusResponse:
{
StatusResponse resp;
resp.wireDecode(*val);
// std::cerr << "StatusReponse: " << resp << std::endl;
if (static_cast<bool>(onFail))
onFail(resp.getInfo());
return;
}
default:
{
if (static_cast<bool>(onFail))
onFail("Invalid response");
return;
}
}
}
} // namespace ndnd
} // namespace ndn