/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014 Steinwurf ApS
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// This object implements network coding in the application layer for
// a encoder - N recoders - decoders topology.
#pragma once
#include <kodocpp/kodocpp.hpp>
class Recoders
{
public:
Recoders (const kodocpp::codec codeType,
const kodocpp::field field, const uint32_t users,
const uint32_t generationSize, const uint32_t packetSize,
const std::vector<ns3::Ptr<ns3::Socket>>& recodersSockets,
const bool recodingFlag, const double transmitProbability)
: m_codeType (codeType),
m_field (field),
m_users (users),
m_generationSize (generationSize),
m_packetSize (packetSize),
m_recodingFlag (recodingFlag),
m_recodersSockets (recodersSockets),
m_transmitProbability (transmitProbability)
{
srand(static_cast<uint32_t>(time(0)));
// Call factories from basic parameters
kodocpp::encoder_factory encoderFactory (m_codeType, m_field,
m_generationSize, m_packetSize);
kodocpp::decoder_factory decoderFactory (m_codeType, m_field,
m_generationSize, m_packetSize);
// Create encoder and disable systematic mode
m_encoder = encoderFactory.build ();
m_encoder.set_systematic_off ();
// Initialize the encoder data buffer
m_encoderBuffer.resize (m_encoder.block_size ());
m_encoder.set_const_symbols (m_encoderBuffer.data (),
m_encoder.block_size ());
m_payload.resize (m_encoder.payload_size ());
// Create recoders and place them in a vector
m_recoderBuffers.resize (m_users);
for (uint32_t n = 0; n < m_users; n++)
{
kodocpp::decoder recoder = decoderFactory.build ();
// Create data buffer for the decoder
m_recoderBuffers[n].resize (recoder.block_size ());
recoder.set_mutable_symbols(m_recoderBuffers[n].data (),
recoder.block_size ());
m_recoders.emplace_back (recoder);
}
// Create decoder and its data buffer
m_decoder = decoderFactory.build ();
m_decoderBuffers.resize (m_decoder.block_size ());
m_decoder.set_mutable_symbols (m_decoderBuffers.data (),
m_decoder.block_size ());
// Initialize transmission counts
m_encoderTransmissionCount = 0;
m_recodersTransmissionCount = 0;
m_decoderRank = 0;
// Initialize previous packets buffer
// m_previousPackets = std::vector<ns3::Ptr<ns3::Packet>> (m_users);
m_uniformRandomVariable = ns3::CreateObject<ns3::UniformRandomVariable> ();
m_uniformRandomVariable->SetAttribute ("Min", ns3::DoubleValue (0.0));
m_uniformRandomVariable->SetAttribute ("Max", ns3::DoubleValue (1.0));
}
void SendPacketEncoder (ns3::Ptr<ns3::Socket> socket, ns3::Time pktInterval)
{
bool allRecodersDecoded = true;
for (auto recoder : m_recoders)
{
allRecodersDecoded &= recoder.is_complete ();
}
if (!allRecodersDecoded)
{
std::cout << "+-----------------------------------+" << std::endl;
std::cout << "|Sending a coded packet from ENCODER|" << std::endl;
std::cout << "+-----------------------------------+" << std::endl;
uint32_t bytesUsed = m_encoder.write_payload (&m_payload[0]);
auto packet = ns3::Create<ns3::Packet> (&m_payload[0], bytesUsed);
socket->Send (packet);
m_encoderTransmissionCount++;
ns3::Simulator::Schedule (pktInterval,
&Recoders::SendPacketEncoder, this,
socket, pktInterval);
}
else
{
socket->Close ();
}
}
void ReceivePacketRecoder (ns3::Ptr<ns3::Socket> socket)
{
// Find the recoder index based on the socket
auto it =
std::find(m_recodersSockets.begin (), m_recodersSockets.end (), socket);
auto id = std::distance (m_recodersSockets.begin (), it);
std::cout << "Received a packet at RECODER " << id + 1 << std::endl;
kodocpp::decoder recoder = m_recoders[id];
auto packet = socket->Recv ();
packet->CopyData (&m_payload[0], recoder.payload_size ());
recoder.read_payload (&m_payload[0]);
// Keep track of the received packets for each recoder
// when no recoding is employed to forward one of them
// uniformly at random
if (!m_recodingFlag)
{
uint32_t index = m_previousPackets[id].size ();
auto relay_it = m_previousPackets[id].find (index);
if (relay_it == m_previousPackets[id].end())
{
m_previousPackets[id][index] = packet;
}
}
if (recoder.is_complete ())
{
std::cout << "RECODER " << id + 1 << " is complete!\n" << std::endl;
}
}
void SendPacketRecoder (ns3::Ptr<ns3::Socket> socket, ns3::Time pktInterval)
{
// Find the recoder index based on the socket
auto it =
std::find(m_recodersSockets.begin (), m_recodersSockets.end (), socket);
auto id = std::distance (m_recodersSockets.begin (), it);
kodocpp::decoder recoder = m_recoders[id];
// A node wil transmit at random with probability
// m_transmitProbability. Thus, we throw a coin
// (RBernoulli Random Variable) with this probability
// and check it. ns-3 does not has Bernoulli but has
// Uniform. So, we convert this random variable through
// the inverse transform method.
bool transmit = false;
if(m_uniformRandomVariable->GetValue () <= m_transmitProbability)
{
transmit = true;
}
if (!m_decoder.is_complete () && recoder.rank () > 0 && transmit)
{
if (m_recodingFlag)
{
std::cout << "+-------------------------------------+" << std::endl;
std::cout << "|Sending a coded packet from RECODER " << id + 1
<< "|" << std::endl;
std::cout << "+-------------------------------------+" << std::endl;
// Recode a new packet and send it
uint32_t bytesUsed = recoder.write_payload (&m_payload[0]);
auto packet = ns3::Create<ns3::Packet> (&m_payload[0], bytesUsed);
socket->Send (packet);
m_recodersTransmissionCount++;
}
else
{
std::cout << "+-------------------------------------------+" << std::endl;
std::cout << "|Forwarding a previous packet from RECODER "
<< id + 1 << "|" << std::endl;
std::cout << "+-------------------------------------------+" << std::endl;
// Get a previously received packet uniformly at random and forward it
uint32_t max = m_previousPackets[id].size ();
uint32_t randomIndex = m_uniformRandomVariable->GetInteger (0, max - 1);
auto packet = m_previousPackets[id][randomIndex];
// Remove all packet tags in order to the callback retag
// them to avoid ~/ns-3-dev/src/common/packet-tag-list.cc,
// line=139 assert failure. Tag removal is shown in
// ~/ns-3-dev/src/applications/udp-echo/udp-echo-server.cc
// for packet forwarding
packet->RemoveAllPacketTags ();
socket->Send (packet);
m_recodersTransmissionCount++;
}
}
// Schedule the next packet
if (!m_decoder.is_complete ())
{
ns3::S