]> git.sesse.net Git - greproxy/blob - rsencoder.cpp
Switch to a different RS encoding.
[greproxy] / rsencoder.cpp
1 #include <string.h>
2 #include <arpa/inet.h>
3 #include <netinet/in.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <sys/select.h>
7 #include <sys/socket.h>
8 extern "C" {
9 #include <fec.h>
10 }
11
12 #include "reorderer.h"
13 #include "rsencoder.h"
14 #include "rs_parm.h"
15
16 #include <algorithm>
17
18 using namespace std;
19         
20 RSEncoder::RSEncoder(Sender *sender) 
21         : sender(sender)
22 {
23         rs = init_rs_char(RS_SYM_SIZE, RS_GF_POLY, 1, 1, RS_PARITY_SIZE, RS_PAD);
24 }
25
26 void RSEncoder::send_packet(uint16_t proto, const std::string &data, int incoming_seq)
27 {
28         if (!packet_history.empty() &&
29             incoming_seq <= packet_history.back().seq) {
30                 // Reorderer should have done this for us.
31                 return;
32         }
33         if (!packet_history.empty() &&
34             incoming_seq / RS_PAYLOAD_SIZE !=
35                 packet_history.back().seq / RS_PAYLOAD_SIZE) {
36                 // Received an unfinished group.
37                 packet_history.clear();
38         }
39         sender->send_packet(proto, data, incoming_seq);
40         packet_history.emplace_back(GREPacket{incoming_seq, proto, data});
41         if (packet_history.size() == RS_PAYLOAD_SIZE) {
42                 finish_group();
43         }
44 }
45
46 void RSEncoder::finish_group()
47 {
48         // Our RS packets need to have the same max length as the longest one.
49         int max_length = 0;
50         for (int i = 0; i < packet_history.size(); ++i) {
51                 max_length = max<int>(max_length, packet_history[i].data.size());
52         }
53
54         vector<string> padded_packets;
55         for (int i = 0; i < packet_history.size(); ++i) {
56                 string p;
57                 p.resize(max_length + 4);
58                 memset(&p[0], 0, max_length + 4);
59                 uint16_t proto_be = htons(packet_history[i].proto);
60                 memcpy(&p[0], &proto_be, sizeof(uint16_t));
61                 uint16_t len_be = htons(packet_history[i].data.size());
62                 memcpy(&p[2], &len_be, sizeof(uint16_t));
63                 memcpy(&p[4], packet_history[i].data.data(), packet_history[i].data.size());
64                 padded_packets.push_back(p);
65         }
66
67         // Now construct RS packets.
68         vector<string> rs_packets;
69         for (int i = 0; i < RS_PARITY_SIZE; ++i) {
70                 string p;
71                 p.resize(max_length + 4);
72                 memset(&p[0], 0, max_length + 4);
73                 rs_packets.push_back(p);
74         }
75         string data, parity;
76         data.resize(RS_PAYLOAD_SIZE);
77         parity.resize(RS_PARITY_SIZE);
78         for (int i = 0; i < max_length + 4; ++i) {
79                 for (int j = 0; j < packet_history.size(); ++j) {
80                         data[j] = packet_history[j].data[i];
81                 }
82                 encode_rs_char(rs,
83                                reinterpret_cast<unsigned char *>(&data[0]),
84                                reinterpret_cast<unsigned char *>(&parity[0]));
85                 for (int j = 0; j < RS_PARITY_SIZE; ++j) {
86                         rs_packets[j][i] = parity[j];
87                 }
88         }
89
90         // Actually send the RS packets.
91         int start_seq = packet_history[0].seq - 1;
92         for (int i = 0; i < RS_PARITY_SIZE; ++i) {
93                 sender->send_packet(0xffff, rs_packets[i], start_seq - i);
94         }
95         
96         packet_history.clear();
97 }
98