/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /** * Copyright (C) 2014 Named Data Networking Project * See COPYING for copyright and distribution information. */ #include "ndnlp-partial-message-store.hpp" namespace nfd { namespace ndnlp { PartialMessage::PartialMessage() : m_fragCount(0) , m_received(0) , m_totalLength(0) { } bool PartialMessage::add(uint16_t fragIndex, uint16_t fragCount, const Block& payload) { if (m_received == 0) { // first packet m_fragCount = fragCount; m_payloads.resize(fragCount); } if (m_fragCount != fragCount || fragIndex >= m_fragCount) { return false; } if (!m_payloads[fragIndex].empty()) { // duplicate return false; } m_payloads[fragIndex] = payload; ++m_received; m_totalLength += payload.value_size(); return true; } bool PartialMessage::isComplete() const { return m_received == m_fragCount; } Block PartialMessage::reassemble() { BOOST_ASSERT(this->isComplete()); ndn::BufferPtr buffer = make_shared(m_totalLength); uint8_t* buf = buffer->get(); for (std::vector::const_iterator it = m_payloads.begin(); it != m_payloads.end(); ++it) { const Block& payload = *it; memcpy(buf, payload.value(), payload.value_size()); buf += payload.value_size(); } return Block(buffer); } PartialMessageStore::PartialMessageStore(Scheduler& scheduler, time::Duration idleDuration) : m_scheduler(scheduler) , m_idleDuration(idleDuration) { } PartialMessageStore::~PartialMessageStore() { } void PartialMessageStore::receiveNdnlpData(const Block& pkt) { NdnlpData parsed; parsed.wireDecode(pkt); if (parsed.m_fragCount == 1) { // single fragment this->onReceive(parsed.m_payload.blockFromValue()); return; } uint64_t messageIdentifier = parsed.m_seq - parsed.m_fragIndex; shared_ptr pm = m_partialMessages[messageIdentifier]; if (!static_cast(pm)) { m_partialMessages[messageIdentifier] = pm = make_shared(); } this->scheduleCleanup(messageIdentifier, pm); pm->add(parsed.m_fragIndex, parsed.m_fragCount, parsed.m_payload); if (pm->isComplete()) { this->onReceive(pm->reassemble()); this->cleanup(messageIdentifier); } } void PartialMessageStore::scheduleCleanup(uint64_t messageIdentifier, shared_ptr partialMessage) { partialMessage->m_expiry = m_scheduler.scheduleEvent(m_idleDuration, bind(&PartialMessageStore::cleanup, this, messageIdentifier)); } void PartialMessageStore::cleanup(uint64_t messageIdentifier) { std::map >::iterator it = m_partialMessages.find(messageIdentifier); if (it == m_partialMessages.end()) { return; } m_scheduler.cancelEvent(it->second->m_expiry); m_partialMessages.erase(it); } } // namespace ndnlp } // namespace nfd