From 63a0866d71f91f19c41244cd32b6954284d547b7 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Sun, 8 Feb 2015 12:47:10 +0100 Subject: [PATCH] Change FEC implementation. We use a longer code to be able to help against longer bursts. Also, switch to fecpp because it's much, much faster (the old library couldn't handle such long codes at the rates we need). --- Makefile | 2 +- rs_parm.h | 3 +-- rsdecoder.cpp | 68 +++++++++++++++++++-------------------------------- rsdecoder.h | 3 ++- rsencoder.cpp | 55 ++++++++++++++++------------------------- rsencoder.h | 3 ++- 6 files changed, 52 insertions(+), 82 deletions(-) diff --git a/Makefile b/Makefile index 4f09820..fe742a6 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ CXXFLAGS=-std=gnu++11 -O2 -g -LDLIBS=-lfec +LDLIBS=-lfecpp TUNGRE_OBJS=tungre.o greprotocol.o reorderer.o tunprotocol.o rsdecoder.o rsencoder.o GREPROXY_OBJS=greproxy.o greprotocol.o reorderer.o tunprotocol.o rsdecoder.o rsencoder.o diff --git a/rs_parm.h b/rs_parm.h index 446f164..3039ef0 100644 --- a/rs_parm.h +++ b/rs_parm.h @@ -7,9 +7,8 @@ #define RS_SYM_SIZE 8 #define RS_NUM_SYM ((1 << RS_SYM_SIZE) - 1) #define RS_PARITY_SIZE 84 -#define RS_PAD 0 +#define RS_PAD 0 // RS_PAD currently needs to be 0. -#define RS_GF_POLY 0x11d // Taken from rstest.c. #define RS_GROUP_SIZE (RS_NUM_SYM - RS_PAD) #define RS_PAYLOAD_SIZE (RS_GROUP_SIZE - RS_PARITY_SIZE) diff --git a/rsdecoder.cpp b/rsdecoder.cpp index 9ba69a5..14527ca 100644 --- a/rsdecoder.cpp +++ b/rsdecoder.cpp @@ -1,23 +1,20 @@ #include #include #include +#include #include #include "rsdecoder.h" #include "rs_parm.h" -extern "C" { -#include -} - #define RS_GROUP_HISTORY 3 using namespace std; RSDecoder::RSDecoder(Sender *sender) - : sender(sender) + : sender(sender), + rs(RS_PAYLOAD_SIZE, RS_GROUP_SIZE) { - rs = init_rs_char(RS_SYM_SIZE, RS_GF_POLY, 1, 1, RS_PARITY_SIZE, RS_PAD); } void RSDecoder::send_packet(uint16_t proto, const std::string &data, int incoming_seq) @@ -86,18 +83,16 @@ void RSDecoder::send_packet(uint16_t proto, const std::string &data, int incomin if (num_regular < RS_PAYLOAD_SIZE) { // Piece the data back into the different RS groups. vector padded_packets; - vector missing_packets; - for (int i = 0; i < RS_GROUP_SIZE; ++i) { - int packet_num = (i < RS_PAYLOAD_SIZE) ? rs_group * RS_PAYLOAD_SIZE + i : - rs_group * RS_PAYLOAD_SIZE - 1 - (i - RS_PAYLOAD_SIZE); + std::map shares; + for (const auto &packet_pair : group.packets) { + int packet_seq = packet_pair.first; + int share_num; string p; p.resize(max_length); - const auto it = group.packets.find(packet_num); - if (it == group.packets.end()) { - missing_packets.push_back(i); - } else if (i < RS_PAYLOAD_SIZE) { + const GREPacket &packet = packet_pair.second; + if (packet_seq >= rs_group * RS_PAYLOAD_SIZE) { // Regular packet. - const GREPacket &packet = it->second; + share_num = packet_seq - rs_group * RS_PAYLOAD_SIZE; uint16_t proto_be = htons(packet.proto); memcpy(&p[0], &proto_be, sizeof(uint16_t)); uint16_t len_be = htons(packet.data.size()); @@ -105,45 +100,32 @@ void RSDecoder::send_packet(uint16_t proto, const std::string &data, int incomin memcpy(&p[4], packet.data.data(), packet.data.size()); } else { // RS packet. - const GREPacket &packet = it->second; + share_num = RS_PAYLOAD_SIZE + (rs_group * RS_PAYLOAD_SIZE - packet_seq - 1); memcpy(&p[0], packet.data.data(), packet.data.size()); } padded_packets.push_back(p); - } - - // Now reconstruct the missing pieces. - unsigned char ch[RS_GROUP_SIZE]; - for (int i = 0; i < max_length; ++i) { - for (int j = 0; j < RS_GROUP_SIZE; ++j) { - ch[j] = padded_packets[j][i]; - } - int ret = decode_rs_char(rs, ch, &missing_packets[0], missing_packets.size()); - if (ret == -1) { - printf("Failed reconstruction!\n"); - // We might get more data later, so don't remove it. - return; - } - for (int j = 0; j < RS_GROUP_SIZE; ++j) { - padded_packets[j][i] = ch[j]; - } + shares[share_num] = reinterpret_cast(padded_packets.back().data()); } // Output all packets we didn't have before. They will come // out-of-order, which will be the job of the Reorderer to fix. - for (int i = 0; i < RS_PAYLOAD_SIZE; ++i) { - int packet_num = rs_group * RS_PAYLOAD_SIZE + i; - if (group.packets.count(packet_num) != 0) { + rs.decode(shares, max_length, [&](size_t share_num, size_t num_shares, const fecpp::byte data[], size_t len){ + if (shares.count(share_num)) { // Already had this packet. - continue; + return; } - const string &p = padded_packets[i]; + int packet_num = rs_group * RS_PAYLOAD_SIZE + share_num; uint16_t proto_be, len_be; - memcpy(&proto_be, &p[0], sizeof(uint16_t)); - memcpy(&len_be, &p[2], sizeof(uint16_t)); - string s(&p[4], &p[4 + ntohs(len_be)]); // TODO: security + memcpy(&proto_be, &data[0], sizeof(uint16_t)); + memcpy(&len_be, &data[2], sizeof(uint16_t)); + string s(&data[4], &data[4 + ntohs(len_be)]); // TODO: security sender->send_packet(ntohs(proto_be), s, packet_num); - printf("Reconstructed packet %d\n", packet_num); - } + const unsigned char *ptr = &data[4]; + printf("Reconstructed packet %d (proto=0x%04x len=%d, data=%02x %02x %02x %02x %02x %02x %02x %02x)\n", packet_num, + ntohs(proto_be), ntohs(len_be), + ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7]); + + }); } group.done = true; diff --git a/rsdecoder.h b/rsdecoder.h index c4303f0..8e63aa6 100644 --- a/rsdecoder.h +++ b/rsdecoder.h @@ -1,6 +1,7 @@ #ifndef _RSDECODER_H #define _RSDECODER_H 1 +#include #include #include @@ -21,7 +22,7 @@ private: }; Sender *sender; std::map rs_groups; - void *rs; + fecpp::fec_code rs; }; #endif /* !defined(_RSDECODER_H) */ diff --git a/rsencoder.cpp b/rsencoder.cpp index d98a13c..dfdbe86 100644 --- a/rsencoder.cpp +++ b/rsencoder.cpp @@ -5,9 +5,7 @@ #include #include #include -extern "C" { -#include -} +#include #include "reorderer.h" #include "rsencoder.h" @@ -18,9 +16,9 @@ extern "C" { using namespace std; RSEncoder::RSEncoder(Sender *sender) - : sender(sender) + : sender(sender), + rs(RS_PAYLOAD_SIZE, RS_GROUP_SIZE) { - rs = init_rs_char(RS_SYM_SIZE, RS_GF_POLY, 1, 1, RS_PARITY_SIZE, RS_PAD); } void RSEncoder::send_packet(uint16_t proto, const std::string &data, int incoming_seq) @@ -51,7 +49,9 @@ void RSEncoder::finish_group() max_length = max(max_length, packet_history[i].data.size()); } - vector padded_packets; + string padded_packets; + padded_packets.reserve((max_length + 4) * packet_history.size()); + // TODO: RS_PAD for (int i = 0; i < packet_history.size(); ++i) { string p; p.resize(max_length + 4); @@ -61,37 +61,24 @@ void RSEncoder::finish_group() uint16_t len_be = htons(packet_history[i].data.size()); memcpy(&p[2], &len_be, sizeof(uint16_t)); memcpy(&p[4], packet_history[i].data.data(), packet_history[i].data.size()); - padded_packets.push_back(p); + padded_packets += p; } - // Now construct RS packets. - vector rs_packets; - for (int i = 0; i < RS_PARITY_SIZE; ++i) { - string p; - p.resize(max_length + 4); - memset(&p[0], 0, max_length + 4); - rs_packets.push_back(p); - } - string data, parity; - data.resize(RS_PAYLOAD_SIZE); - parity.resize(RS_PARITY_SIZE); - for (int i = 0; i < max_length + 4; ++i) { - for (int j = 0; j < packet_history.size(); ++j) { - data[j] = packet_history[j].data[i]; - } - encode_rs_char(rs, - reinterpret_cast(&data[0]), - reinterpret_cast(&parity[0])); - for (int j = 0; j < RS_PARITY_SIZE; ++j) { - rs_packets[j][i] = parity[j]; - } - } + // Now construct and send RS packets. + rs.encode(reinterpret_cast(padded_packets.data()), + padded_packets.size(), + [&](size_t packet_num, size_t num_packets, const fecpp::byte data[], size_t size) { + // The first N packets are just the original ones; ignore them. + if (packet_num < RS_PAYLOAD_SIZE) { + return; + } - // Actually send the RS packets. - int start_seq = packet_history[0].seq - 1; - for (int i = 0; i < RS_PARITY_SIZE; ++i) { - sender->send_packet(0xffff, rs_packets[i], start_seq - i); - } + const char *sdata = reinterpret_cast(data); + int start_seq = packet_history[0].seq - 1; + for (int i = 0; i < RS_PARITY_SIZE; ++i) { + sender->send_packet(0xffff, string(sdata, size), start_seq - (packet_num - RS_PAYLOAD_SIZE)); + } + }); packet_history.clear(); } diff --git a/rsencoder.h b/rsencoder.h index ef8f289..6ab6e4b 100644 --- a/rsencoder.h +++ b/rsencoder.h @@ -2,6 +2,7 @@ #define _RSENCODER_H 1 #include +#include #include #include @@ -20,7 +21,7 @@ private: Sender *sender; std::vector packet_history; - void *rs; + fecpp::fec_code rs; }; #endif // !defined(_RSENCODER_H) -- 2.39.2