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 // Licensed under the License terms and conditions for use, reproduction, and
6 // distribution of 5G-MAG software (the “License”). You may not use this file
7 // except in compliance with the License. You may obtain a copy of the License at
8 // https://www.5g-mag.com/reference-tools. Unless required by applicable law or
9 // agreed to in writing, software distributed under the License is distributed on
10 // an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 // or implied.
12 //
13 // See the License for the specific language governing permissions and limitations
14 // under the License.
15 //
16 #include <stdexcept>
17 #include <cstring>
18 #include <iostream>
19 #include <arpa/inet.h>
20 #include "AlcPacket.h"
21 
22 LibFlute::AlcPacket::AlcPacket(char* data, size_t len)
23 {
24  if (len < 4) {
25  throw std::runtime_error("Packet too short");
26  }
27 
28  std::memcpy(&_lct_header, data, 4);
29  if (_lct_header.version != 1) {
30  throw std::runtime_error("Unsupported LCT version");
31  }
32 
33  char* hdr_ptr = data + 4;
34  if (_lct_header.congestion_control_flag != 0) {
35  throw std::runtime_error("Unsupported CCI field length");
36  }
37  // [TODO] read CCI
38  hdr_ptr += 4;
39 
40  if (_lct_header.half_word_flag == 0 && _lct_header.tsi_flag == 0) {
41  throw std::runtime_error("TSI field not present");
42  }
43  auto tsi_shift = 0;
44  if(_lct_header.half_word_flag == 1) {
45  _tsi = ntohs(*(uint16_t*)hdr_ptr);
46  tsi_shift = 16;
47  hdr_ptr += 2;
48  }
49  if(_lct_header.tsi_flag == 1) {
50  _tsi |= ntohl(*(uint32_t*)hdr_ptr) << tsi_shift;
51  hdr_ptr += 4;
52  }
53 
54  if ( _lct_header.close_session_flag == 0 && _lct_header.half_word_flag == 0 && _lct_header.toi_flag == 0) {
55  throw std::runtime_error("TOI field not present");
56  }
57  auto toi_shift = 0;
58  if(_lct_header.half_word_flag == 1) {
59  _toi = ntohs(*(uint16_t*)hdr_ptr);
60  toi_shift = 16;
61  hdr_ptr += 2;
62  }
63  switch(_lct_header.toi_flag) {
64  case 0: break;
65  case 1:
66  _toi |= ntohl(*(uint32_t*)hdr_ptr) << toi_shift;
67  hdr_ptr += 4;
68  break;
69  case 2:
70  if (toi_shift > 0) {
71  throw std::runtime_error("TOI fields over 64 bits in length are not supported");
72  } else {
73  _toi = ntohl(*(uint32_t*)hdr_ptr);
74  hdr_ptr += 4;
75  _toi |= (uint64_t)(ntohl(*(uint32_t*)hdr_ptr)) << 32;
76  hdr_ptr += 4;
77  }
78  break;
79  default:
80  throw std::runtime_error("TOI fields over 64 bits in length are not supported");
81  }
82 
83  if (_lct_header.codepoint == 0) {
85  } else {
86  throw std::runtime_error("Only Compact No-Code FEC is supported");
87  }
88 
89  auto expected_header_len = 2 +
90  _lct_header.congestion_control_flag +
91  _lct_header.half_word_flag +
92  _lct_header.tsi_flag +
93  _lct_header.toi_flag;
94 
95  size_t ext_header_len = (_lct_header.lct_header_len - expected_header_len) * 4;
96  while (ext_header_len > 0) {
97  auto ext_ptr = hdr_ptr;
98  uint8_t het = *ext_ptr;
99  ext_ptr += 1; // Skip HET
100  uint8_t hel = 0;
101  size_t ext_len = 4;
102  if (het <= 127) {
103  hel = *ext_ptr;
104  ext_len = hel * 4;
105  ext_ptr += 1; // Skip HEL
106  }
107 
108  if (ext_len > ext_header_len) {
109  throw std::runtime_error("Header extension length exceeds remaining header length");
110  }
111 
112  switch ((AlcPacket::HeaderExtension)het) {
113  case EXT_NOP:
114  case EXT_AUTH:
115  case EXT_TIME: {
116  break; // ignored
117  }
118  case EXT_FTI: {
119  if (_fec_oti.encoding_id == FecScheme::CompactNoCode) {
120  if (hel != 4) {
121  throw std::runtime_error("Invalid length for EXT_FTI header extension");
122  }
123  _fec_oti.transfer_length = (uint64_t)(ntohs(*(uint16_t*)ext_ptr)) << 32;
124  ext_ptr += 2;
125  _fec_oti.transfer_length |= (uint64_t)(ntohl(*(uint32_t*)ext_ptr));
126  ext_ptr += 4;
127  ext_ptr += 2; // reserved
128  _fec_oti.encoding_symbol_length = ntohs(*(uint16_t*)ext_ptr);
129  ext_ptr += 2;
130  _fec_oti.max_source_block_length = ntohl(*(uint32_t*)ext_ptr);
131  }
132  break;
133  }
134  case EXT_FDT: {
135  uint8_t flute_version = (*ext_ptr & 0xF0) >> 4;
136  if (flute_version > 2) {
137  throw std::runtime_error("Unsupported FLUTE version");
138  }
139  _fdt_instance_id = (*ext_ptr & 0x0F) << 16;
140  ext_ptr++;
141  _fdt_instance_id |= ntohs(*(uint16_t*)ext_ptr);
142  break;
143  }
144  case EXT_CENC: {
145  uint8_t encoding = *ext_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  break;
153  }
154  }
155 
156  ext_header_len -= ext_len;
157  hdr_ptr += ext_len;
158  }
159 }
160 
161 LibFlute::AlcPacket::AlcPacket(uint16_t tsi, uint16_t toi, LibFlute::FecOti fec_oti, const std::vector<LibFlute::EncodingSymbol>& symbols, size_t max_encoding_symbol_size, uint32_t fdt_instance_id)
162  : _fec_oti(fec_oti)
163 {
164  const size_t max_alc_header_size = 4;
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_encoding_symbol_size +
171  lct_header_len * 4
172  + max_alc_header_size ;
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_encoding_symbol_size + max_alc_header_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  // EXT_FTI Transfer Length is a 48-bit field (RFC 5052 Compact No-Code FTI):
208  // high 16 bits then low 32 bits, matching the decoder above
209  // ((hi16 << 32) | lo32). The previous masks (& 0x00FF0000) >> 32 (always 0)
210  // and & 0x0000FFFF (low 16 bits only) truncated the length to 16 bits, so any
211  // object > 64 KB was signalled with a bogus tiny length -> the receiver
212  // under-allocated source blocks and rejected the real symbols.
213  *((uint16_t*)hdr_ptr) = htons(static_cast<uint16_t>((_fec_oti.transfer_length >> 32) & 0xFFFF));
214  hdr_ptr += 2;
215  *((uint32_t*)hdr_ptr) = htonl(static_cast<uint32_t>(_fec_oti.transfer_length & 0xFFFFFFFF));
216  hdr_ptr += 4;
217  hdr_ptr += 2; // reserved
218  *((uint16_t*)hdr_ptr) = htons(_fec_oti.encoding_symbol_length);
219  hdr_ptr += 2;
220  *((uint32_t*)hdr_ptr) = htonl(_fec_oti.max_source_block_length);
221  }
222 }
223 
225 {
226  if (_buffer) free(_buffer);
227 }
uint64_t tsi() const
Get the TSI.
Definition: AlcPacket.h:57
char * data() const
Get a pointer to the payload data of the constructed packet.
Definition: AlcPacket.h:92
uint32_t fdt_instance_id() const
Get the FDT instance ID.
Definition: AlcPacket.h:77
~AlcPacket()
Default destructor.
Definition: AlcPacket.cpp:224
uint64_t toi() const
Get the TOI.
Definition: AlcPacket.h:62
AlcPacket(char *data, size_t len)
Create an ALC packet from payload data.
Definition: AlcPacket.cpp:22
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:51
uint64_t transfer_length
Definition: flute_types.h:54
FecScheme encoding_id
Definition: flute_types.h:52
uint32_t max_source_block_length
Definition: flute_types.h:56
uint32_t encoding_symbol_length
Definition: flute_types.h:55