| /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ |
| /** |
| * Copyright (c) 2014-2016, Regents of the University of California. |
| * |
| * This file is part of NDNS (Named Data Networking Domain Name Service). |
| * See AUTHORS.md for complete list of NDNS authors and contributors. |
| * |
| * NDNS is free software: you can redistribute it and/or modify it under the terms |
| * of the GNU General Public License as published by the Free Software Foundation, |
| * either version 3 of the License, or (at your option) any later version. |
| * |
| * NDNS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; |
| * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
| * PURPOSE. See the GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License along with |
| * NDNS, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>. |
| */ |
| |
| #include "response.hpp" |
| #include "logger.hpp" |
| |
| namespace ndn { |
| namespace ndns { |
| |
| Response::Response() |
| : m_ndnsType(NDNS_RAW) |
| , m_freshnessPeriod(DEFAULT_RR_FRESHNESS_PERIOD) |
| , m_appContent(makeBinaryBlock(ndn::tlv::Content, reinterpret_cast<const uint8_t*>(0), 0)) |
| { |
| } |
| |
| Response::Response(const Name& zone, const name::Component& queryType) |
| : m_zone(zone) |
| , m_queryType(queryType) |
| , m_ndnsType(NDNS_RAW) |
| , m_freshnessPeriod(DEFAULT_RR_FRESHNESS_PERIOD) |
| , m_appContent(makeBinaryBlock(ndn::tlv::Content, reinterpret_cast<const uint8_t*>(0), 0)) |
| { |
| } |
| |
| template<bool T> |
| inline size_t |
| Response::wireEncode(EncodingImpl<T>& block) const |
| { |
| if (m_ndnsType == NDNS_RAW) { |
| // Raw application content |
| return block.prependBlock(m_appContent); |
| } |
| |
| // Content :: = CONTENT-TYPE TLV-LENGTH |
| // Block* |
| |
| size_t totalLength = 0; |
| for (std::vector<Block>::const_reverse_iterator iter = m_rrs.rbegin(); |
| iter != m_rrs.rend(); ++iter) { |
| totalLength += block.prependBlock(*iter); |
| } |
| |
| totalLength += block.prependVarNumber(totalLength); |
| totalLength += block.prependVarNumber(::ndn::tlv::Content); |
| |
| return totalLength; |
| } |
| |
| const Block |
| Response::wireEncode() const |
| { |
| if (m_ndnsType == NDNS_RAW) { |
| return m_appContent; |
| } |
| |
| EncodingEstimator estimator; |
| size_t estimatedSize = wireEncode(estimator); |
| EncodingBuffer buffer(estimatedSize, 0); |
| wireEncode(buffer); |
| return buffer.block(); |
| } |
| |
| void |
| Response::wireDecode(const Block& wire) |
| { |
| if (m_ndnsType == NDNS_RAW) { |
| m_appContent = wire; |
| return; |
| } |
| |
| wire.parse(); |
| |
| Block::element_const_iterator iter = wire.elements().begin(); |
| for (; iter != wire.elements().end(); ++iter) { |
| m_rrs.push_back(*iter); |
| } |
| } |
| |
| bool |
| Response::fromData(const Name& hint, const Name& zone, const Data& data) |
| { |
| label::MatchResult re; |
| if (!matchName(data, hint, zone, re)) |
| return false; |
| |
| m_rrLabel = re.rrLabel; |
| m_rrType = re.rrType; |
| m_version = re.version; |
| |
| m_zone = zone; |
| size_t len = zone.size(); |
| if (!hint.empty()) |
| len += hint.size() + 1; |
| m_queryType = data.getName().get(len); |
| |
| MetaInfo info = data.getMetaInfo(); |
| |
| m_freshnessPeriod = time::duration_cast<time::seconds>(info.getFreshnessPeriod()); |
| const Block* block = info.findAppMetaInfo(tlv::NdnsType); |
| if (block != 0) |
| m_ndnsType = static_cast<NdnsType>(readNonNegativeInteger(*block)); |
| |
| wireDecode(data.getContent()); |
| return true; |
| } |
| |
| |
| shared_ptr<Data> |
| Response::toData() |
| { |
| Name name; |
| name.append(m_zone) |
| .append(m_queryType) |
| .append(m_rrLabel) |
| .append(m_rrType); |
| |
| if (m_version.empty()) { |
| name.appendVersion(); |
| m_version = name.get(-1); |
| } |
| else { |
| name.append(m_version); |
| } |
| |
| shared_ptr<Data> data = make_shared<Data>(name); |
| |
| MetaInfo info; |
| info.setFreshnessPeriod(m_freshnessPeriod); |
| |
| if (m_ndnsType != NDNS_RAW) { |
| info.addAppMetaInfo(makeNonNegativeIntegerBlock(ndns::tlv::NdnsType, m_ndnsType)); |
| data->setContent(this->wireEncode()); |
| } |
| else { |
| data->setContent(m_appContent); |
| } |
| data->setMetaInfo(info); |
| |
| return data; |
| } |
| |
| |
| Response& |
| Response::addRr(const Block& rr) |
| { |
| this->m_rrs.push_back(rr); |
| return *this; |
| } |
| |
| Response& |
| Response::addRr(const std::string& rr) |
| { |
| return this->addRr(makeBinaryBlock(ndns::tlv::RrData, rr.c_str(), rr.size())); |
| } |
| |
| bool |
| Response::removeRr(const Block& rr) |
| { |
| for (std::vector<Block>::iterator iter = m_rrs.begin(); iter != m_rrs.end(); ++iter) { |
| if (*iter == rr) { |
| m_rrs.erase(iter); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| void |
| Response::setAppContent(const Block& block) |
| { |
| if (block.type() != ndn::tlv::Content) { |
| m_appContent = Block(ndn::tlv::Content, block); |
| } else |
| m_appContent = block; |
| |
| m_appContent.encode(); // this is a must |
| } |
| |
| |
| bool |
| Response::operator==(const Response& other) const |
| { |
| bool tmp = (getZone() == other.getZone() && |
| getQueryType() == other.getQueryType() && getRrLabel() == other.getRrLabel() && |
| getRrType() == other.getRrType() && getVersion() == other.getVersion() && |
| getNdnsType() == other.getNdnsType()); |
| |
| if (tmp == false) |
| return tmp; |
| |
| if (m_ndnsType == NDNS_RAW) { |
| return tmp && (getAppContent() == other.getAppContent()); |
| } |
| else |
| return tmp && getRrs() == other.getRrs(); |
| } |
| |
| std::ostream& |
| operator<<(std::ostream& os, const Response& response) |
| { |
| os << "Response: zone=" << response.getZone() |
| << " queryType=" << response.getQueryType() |
| << " rrLabel=" << response.getRrLabel() |
| << " rrType=" << response.getRrType() |
| << " version=" << response.getVersion() |
| << " freshnessPeriod=" << response.getFreshnessPeriod() |
| << " ndnsType=" << response.getNdnsType(); |
| if (response.getNdnsType() == NDNS_RAW) { |
| if (response.getAppContent().empty()) |
| os << " appContent=NULL"; |
| else |
| os << " appContentSize=" << response.getAppContent().size(); |
| } |
| else { |
| os << " rrs.size=" << response.getRrs().size(); |
| } |
| return os; |
| } |
| } // namespace ndns |
| } // namespace ndn |