X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=rsencoder.cpp;fp=rsencoder.cpp;h=3026dd4d2373fdc552fbe1660ab88dbf37ce818e;hb=9e8a28e92f8e092a2409ddad770b3dbe088a4fe9;hp=0000000000000000000000000000000000000000;hpb=827d71d4ad6f75eadaf6794e8abab0c71ea29ee6;p=greproxy diff --git a/rsencoder.cpp b/rsencoder.cpp new file mode 100644 index 0000000..3026dd4 --- /dev/null +++ b/rsencoder.cpp @@ -0,0 +1,92 @@ +#include +#include +#include +#include +#include +#include +#include +extern "C" { +#include +} + +#include "reorderer.h" +#include "rsencoder.h" +#include "rs_parm.h" + +#include + +using namespace std; + +void RSEncoder::send_packet(uint16_t proto, const std::string &data, int incoming_seq) +{ + if (!packet_history.empty() && + incoming_seq <= packet_history.back().seq) { + // Reorderer should have done this for us. + return; + } + if (!packet_history.empty() && + incoming_seq / RS_PAYLOAD_SIZE != + packet_history.back().seq / RS_PAYLOAD_SIZE) { + // Received an unfinished group. + packet_history.clear(); + } + sender->send_packet(proto, data, incoming_seq); + packet_history.emplace_back(GREPacket{incoming_seq, proto, data}); + if (packet_history.size() == RS_PAYLOAD_SIZE) { + finish_group(); + } +} + +void RSEncoder::finish_group() +{ + // Our RS packets need to have the same max length as the longest one. + int max_length = 0; + for (int i = 0; i < packet_history.size(); ++i) { + max_length = max(max_length, packet_history[i].data.size()); + } + + vector padded_packets; + for (int i = 0; i < packet_history.size(); ++i) { + string p; + p.resize(max_length + 4); + memset(&p[0], 0, max_length + 4); + uint16_t proto_be = htons(packet_history[i].proto); + memcpy(&p[0], &proto_be, sizeof(uint16_t)); + 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); + } + + // 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_8(reinterpret_cast(&data[0]), + reinterpret_cast(&parity[0]), + RS_PAD); + for (int j = 0; j < RS_PARITY_SIZE; ++j) { + rs_packets[j][i] = parity[j]; + } + } + + // 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); + } + + packet_history.clear(); +} +