libflute
AlcPacket.cpp
Go to the documentation of this file.
1 // libflute - FLUTE/ALC library
2 //
3 // Copyright (C) 2021 Klaus Kühnhammer (Österreichische Rundfunksender GmbH & Co KG)
4 //
5 // This program is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU Affero General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU Affero General Public License for more details.
14 //
15 // You should have received a copy of the GNU Affero General Public License
16 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 //
18 #include <cstdio>
19 #include <cstring>
20 #include <iostream>
21 #include <arpa/inet.h>
22 #include "AlcPacket.h"
23 
24 LibFlute::AlcPacket::AlcPacket(char* data, size_t len)
25 {
26  if (len < 4) {
27  throw "Packet too short";
28  }
29 
30  std::memcpy(&_lct_header, data, 4);
31  if (_lct_header.version != 1) {
32  throw "Unsupported LCT version";
33  }
34 
35  char* hdr_ptr = data + 4;
36  if (_lct_header.congestion_control_flag != 0) {
37  throw "Unsupported CCI field length";
38  }
39  // [TODO] read CCI
40  hdr_ptr += 4;
41 
42  if (_lct_header.half_word_flag == 0 && _lct_header.tsi_flag == 0) {
43  throw "TSI field not present";
44  }
45  auto tsi_shift = 0;
46  if(_lct_header.half_word_flag == 1) {
47  _tsi = ntohs(*(uint16_t*)hdr_ptr);
48  tsi_shift = 16;
49  hdr_ptr += 2;
50  }
51  if(_lct_header.tsi_flag == 1) {
52  _tsi |= ntohl(*(uint32_t*)hdr_ptr) << tsi_shift;
53  hdr_ptr += 4;
54  }
55 
56  if ( _lct_header.close_session_flag == 0 && _lct_header.half_word_flag == 0 && _lct_header.toi_flag == 0) {
57  throw "TOI field not present";
58  }
59  auto toi_shift = 0;
60  if(_lct_header.half_word_flag == 1) {
61  _toi = ntohs(*(uint16_t*)hdr_ptr);
62  toi_shift = 16;
63  hdr_ptr += 2;
64  }
65  switch(_lct_header.toi_flag) {
66  case 0: break;
67  case 1:
68  _toi |= ntohl(*(uint32_t*)hdr_ptr) << toi_shift;
69  hdr_ptr += 4;
70  break;
71  case 2:
72  if (toi_shift > 0) {
73  throw "TOI fields over 64 bits in length are not supported";
74  } else {
75  _toi = ntohl(*(uint32_t*)hdr_ptr);
76  hdr_ptr += 4;
77  _toi |= (uint64_t)(ntohl(*(uint32_t*)hdr_ptr)) << 32;
78  hdr_ptr += 4;
79  }
80  break;
81  default:
82  throw "TOI fields over 64 bits in length are not supported";
83  break;
84  }
85 
86  if (_lct_header.codepoint == 0) {
88  } else {
89  throw "Only Compact No-Code FEC is supported";
90  }
91 
92  auto expected_header_len = 2 +
93  _lct_header.congestion_control_flag +
94  _lct_header.half_word_flag +
95  _lct_header.tsi_flag +
96  _lct_header.toi_flag;
97 
98  auto ext_header_len = (_lct_header.lct_header_len - expected_header_len) * 4;
99 
100  while (ext_header_len > 0) {
101  uint8_t het = *hdr_ptr;
102  hdr_ptr += 1;
103  uint8_t hel = 0;
104  if (het < 128) {
105  hel = *hdr_ptr;
106  hdr_ptr += 1;
107  }
108 
109  switch ((AlcPacket::HeaderExtension)het) {
110  case EXT_NOP:
111  case EXT_AUTH:
112  case EXT_TIME: {
113  hdr_ptr += 3;
114  break; // ignored
115  }
116  case EXT_FTI: {
117  if (_fec_oti.encoding_id == FecScheme::CompactNoCode) {
118  if (hel != 4) {
119  throw "Invalid length for EXT_FTI header extension";
120  }
121  _fec_oti.transfer_length = (uint64_t)(ntohs(*(uint16_t*)hdr_ptr)) << 32;
122  hdr_ptr += 2;
123  _fec_oti.transfer_length |= (uint64_t)(ntohl(*(uint32_t*)hdr_ptr));
124  hdr_ptr += 4;
125  hdr_ptr += 2; // reserved
126  _fec_oti.encoding_symbol_length = ntohs(*(uint16_t*)hdr_ptr);
127  hdr_ptr += 2;
128  _fec_oti.max_source_block_length = ntohl(*(uint32_t*)hdr_ptr);
129  hdr_ptr += 4;
130  }
131  break;
132  }
133  case EXT_FDT: {
134  uint8_t flute_version = (*hdr_ptr & 0xF0) >> 4;
135  if (flute_version > 2) {
136  throw "Unsupported FLUTE version";
137  }
138  _fdt_instance_id = (*hdr_ptr & 0x0F) << 16;
139  hdr_ptr++;
140  _fdt_instance_id |= ntohs(*(uint16_t*)hdr_ptr);
141  hdr_ptr += 2;
142  break;
143  }
144  case EXT_CENC: {
145  uint8_t encoding = *hdr_ptr;
146  switch (encoding) {
147  case 0: _content_encoding = ContentEncoding::NONE; break;
148  case 1: _content_encoding = ContentEncoding::ZLIB; break;
149  case 2: _content_encoding = ContentEncoding::DEFLATE; break;
150  case 3: _content_encoding = ContentEncoding::GZIP; break;
151  }
152  hdr_ptr += 3;
153  break;
154  }
155  }
156 
157  ext_header_len -= 4;
158  ext_header_len -= hel * 4;
159  }
160 }
161 
162 LibFlute::AlcPacket::AlcPacket(uint16_t tsi, uint16_t toi, LibFlute::FecOti fec_oti, const std::vector<LibFlute::EncodingSymbol>& symbols, size_t max_size, uint32_t fdt_instance_id)
163  : _fec_oti(fec_oti)
164 {
165  auto lct_header_len = 3;
166  if (toi == 0) { // Add extensions for FDT
167  lct_header_len += 5;
168  }
169 
170  auto max_packet_length = max_size +
171  lct_header_len * 4
172  + 4 ;
173 
174  _buffer = (char*)calloc(max_packet_length, sizeof(char));
175 
176  auto lct_header = (lct_header_t*)_buffer;
177 
178  lct_header->version = 1;
179  lct_header->half_word_flag = 1;
180  lct_header->lct_header_len = lct_header_len;
181  auto hdr_ptr = _buffer + 4;
182  auto payload_ptr = _buffer + 4 * lct_header_len;
183 
184  auto payload_size = EncodingSymbol::to_payload(symbols, payload_ptr, max_size, _fec_oti, ContentEncoding::NONE);
185  _len = 4 * lct_header_len + payload_size;
186 
187  hdr_ptr += 4; // CCI = 0
188 
189  *((uint16_t*)hdr_ptr) = htons(tsi);
190  hdr_ptr += 2;
191 
192  *((uint16_t*)hdr_ptr) = htons(toi);
193  hdr_ptr += 2;
194 
195  if (toi == 0) { // Add extensions for FDT
196  *((uint8_t*)hdr_ptr) = EXT_FDT;
197  hdr_ptr += 1;
198  *((uint8_t*)hdr_ptr) = 1 << 4 | (fdt_instance_id & 0x000F0000) >> 16;
199  hdr_ptr += 1;
200  *((uint16_t*)hdr_ptr) = htons(fdt_instance_id & 0x0000FFFF);
201  hdr_ptr += 2;
202 
203  *((uint8_t*)hdr_ptr) = EXT_FTI;
204  hdr_ptr += 1;
205  *((uint8_t*)hdr_ptr) = 4; // HEL
206  hdr_ptr += 1;
207  *((uint16_t*)hdr_ptr) = htons((_fec_oti.transfer_length & 0x00FF0000) >> 32);
208  hdr_ptr += 2;
209  *((uint32_t*)hdr_ptr) = htonl(_fec_oti.transfer_length & 0x0000FFFF);
210  hdr_ptr += 4;
211  hdr_ptr += 2; // reserved
212  *((uint16_t*)hdr_ptr) = htons(_fec_oti.encoding_symbol_length);
213  hdr_ptr += 2;
214  *((uint32_t*)hdr_ptr) = htonl(_fec_oti.max_source_block_length);
215  hdr_ptr += 4;
216  }
217 
218 
219 
220  /*
221  memset(&_lct_header, 0, sizeof(_lct_header));
222  _lct_header.version = 1;
223  _lct_header.half_word_flag = 1;
224  if (fec_scheme == LibFlute::FecScheme::CompactNoCode) {
225  _lct_header.codepoint = 0;
226  } else {
227  throw "Only Compact No-Code FEC is supported";
228  }
229  */
230 
231 }
232 
234 {
235  if (_buffer) free(_buffer);
236 }
uint64_t tsi() const
Get the TSI.
Definition: AlcPacket.h:59
char * data() const
Get a pointer to the payload data of the constructed packet.
Definition: AlcPacket.h:94
uint32_t fdt_instance_id() const
Get the FDT instance ID.
Definition: AlcPacket.h:79
~AlcPacket()
Default destructor.
Definition: AlcPacket.cpp:233
uint64_t toi() const
Get the TOI.
Definition: AlcPacket.h:64
AlcPacket(char *data, size_t len)
Create an ALC packet from payload data.
Definition: AlcPacket.cpp:24
static size_t to_payload(const std::vector< EncodingSymbol > &, char *encoded_data, size_t data_len, const FecOti &fec_oti, ContentEncoding encoding)
Write encoding symbols to a packet payload buffer.
OTI values struct.
Definition: flute_types.h:53
uint64_t transfer_length
Definition: flute_types.h:55
FecScheme encoding_id
Definition: flute_types.h:54
uint32_t max_source_block_length
Definition: flute_types.h:57
uint32_t encoding_symbol_length
Definition: flute_types.h:56