]> git.sesse.net Git - greproxy/commitdiff
Change FEC implementation.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 8 Feb 2015 11:47:10 +0000 (12:47 +0100)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 8 Feb 2015 11:47:10 +0000 (12:47 +0100)
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
rs_parm.h
rsdecoder.cpp
rsdecoder.h
rsencoder.cpp
rsencoder.h

index 4f098204b173c0ba475518b2f3a7d3d69077f292..fe742a68849838046f00b2ec1e5fedf7e75700b7 100644 (file)
--- 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
index 446f1640f8fa0146d2865583dc540a85b8bfa84d..3039ef0eff9ad96668a4a75a0d7bf33e2438e20a 100644 (file)
--- 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)
 
index 9ba69a504ef98cf9bcd971e06b93f59e4e60103a..14527ca06cea226d9ad0dff1e1a458a0e82564a8 100644 (file)
@@ -1,23 +1,20 @@
 #include <stdio.h>
 #include <string.h>
 #include <arpa/inet.h>
+#include <fecpp.h>
 
 #include <map>
 #include "rsdecoder.h"
 #include "rs_parm.h"
 
-extern "C" {
-#include <fec.h>
-}
-
 #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<string> padded_packets;
-                       vector<int> 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<size_t, const fecpp::byte *> 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<const fecpp::byte *>(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;
index c4303f00cb543d0d4110c9d3f2dba641531324b6..8e63aa67a8a7b12b0bd8c708d3d38279f9c20ae6 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _RSDECODER_H
 #define _RSDECODER_H 1
 
+#include <fecpp.h>
 #include <stdint.h>
 
 #include <map>
@@ -21,7 +22,7 @@ private:
        };
        Sender *sender;
        std::map<int, RSGroup> rs_groups;
-       void *rs;
+       fecpp::fec_code rs;
 };
 
 #endif  /* !defined(_RSDECODER_H) */
index d98a13caf16cb9612965915a501f833a820cc96a..dfdbe86a4f62de6de3f609a9214393452b62936f 100644 (file)
@@ -5,9 +5,7 @@
 #include <stdlib.h>
 #include <sys/select.h>
 #include <sys/socket.h>
-extern "C" {
-#include <fec.h>
-}
+#include <fecpp.h>
 
 #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<int>(max_length, packet_history[i].data.size());
        }
 
-       vector<string> 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<string> 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<unsigned char *>(&data[0]),
-                              reinterpret_cast<unsigned char *>(&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<const fecpp::byte*>(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<const char *>(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();
 }
index ef8f2893451ab67e1308bd4c813ba47665b105c9..6ab6e4b2de6f140a20fe02ce876431fcccc13ca4 100644 (file)
@@ -2,6 +2,7 @@
 #define _RSENCODER_H 1
 
 #include <stdint.h>
+#include <fecpp.h>
 
 #include <string>
 #include <vector>
@@ -20,7 +21,7 @@ private:
 
        Sender *sender;
        std::vector<GREPacket> packet_history;
-       void *rs;
+       fecpp::fec_code rs;
 };
 
 #endif  // !defined(_RSENCODER_H)