| /* -*- 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 |