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 <cstring>
17 #include <iostream>
18 #include <arpa/inet.h>
19 #include "AlcPacket.h"
20 
21 LibFlute::AlcPacket::AlcPacket(char* data, size_t len)
22 {
23  if (len < 4) {
24  throw "Packet too short";
25  }
26 
27  std::memcpy(&_lct_header, data, 4);
28  if (_lct_header.version != 1) {
29  throw "Unsupported LCT version";
30  }
31 
32  char* hdr_ptr = data + 4;
33  if (_lct_header.congestion_control_flag != 0) {
34  throw "Unsupported CCI field length";
35  }
36  // [TODO] read CCI
37  hdr_ptr += 4;
38 
39  if (_lct_header.half_word_flag == 0 && _lct_header.tsi_flag == 0) {
40  throw "TSI field not present";
41  }
42  auto tsi_shift = 0;
43  if(_lct_header.half_word_flag == 1) {
44  _tsi = ntohs(*(uint16_t*)hdr_ptr);
45  tsi_shift = 16;
46  hdr_ptr += 2;
47  }
48  if(_lct_header.tsi_flag == 1) {
49  _tsi |= ntohl(*(uint32_t*)hdr_ptr) << tsi_shift;
50  hdr_ptr += 4;
51  }
52 
53  if ( _lct_header.close_session_flag == 0 && _lct_header.half_word_flag == 0 && _lct_header.toi_flag == 0) {
54  throw "TOI field not present";
55  }
56  auto toi_shift = 0;
57  if(_lct_header.half_word_flag == 1) {
58  _toi = ntohs(*(uint16_t*)hdr_ptr);
59  toi_shift = 16;
60  hdr_ptr += 2;
61  }
62  switch(_lct_header.toi_flag) {
63  case 0: break;
64  case 1:
65  _toi |= ntohl(*(uint32_t*)hdr_ptr) << toi_shift;
66  hdr_ptr += 4;
67  break;
68  case 2:
69  if (toi_shift > 0) {
70  throw "TOI fields over 64 bits in length are not supported";
71  } else {
72  _toi = ntohl(*(uint32_t*)hdr_ptr);
73  hdr_ptr += 4;
74  _toi |= (uint64_t)(ntohl(*(uint32_t*)hdr_ptr)) << 32;
75  hdr_ptr += 4;
76  }
77  break;
78  default:
79  throw "TOI fields over 64 bits in length are not supported";
80  }
81 
82  if (_lct_header.codepoint == 0) {
84  } else {
85  throw "Only Compact No-Code FEC is supported";
86  }
87 
88  auto expected_header_len = 2 +
89  _lct_header.congestion_control_flag +
90  _lct_header.half_word_flag +
91  _lct_header.tsi_flag +
92  _lct_header.toi_flag;
93 
94  size_t ext_header_len = (_lct_header.lct_header_len - expected_header_len) * 4;
95  while (ext_header_len > 0) {
96  auto ext_ptr = hdr_ptr;
97  uint8_t het = *ext_ptr;
98  ext_ptr += 1; // Skip HET
99  uint8_t hel = 0;
100  size_t ext_len = 4;
101  if (het <= 127) {
102  hel = *ext_ptr;
103  ext_len = hel * 4;
104  ext_ptr += 1; // Skip HEL
105  }
106 
107  if (ext_len > ext_header_len) {
108  throw "Header extension length exceeds remaining header length";
109  }
110 
111  switch ((AlcPacket::HeaderExtension)het) {
112  case EXT_NOP:
113  case EXT_AUTH:
114  case EXT_TIME: {
115  break; // ignored
116  }
117  case EXT_FTI: {
118  if (_fec_oti.encoding_id == FecScheme::CompactNoCode) {
119  if (hel != 4) {
120  throw "Invalid length for EXT_FTI header extension";
121  }
122  _fec_oti.transfer_length = (uint64_t)(ntohs(*(uint16_t*)ext_ptr)) << 32;
123  ext_ptr += 2;
124  _fec_oti.transfer_length |= (uint64_t)(ntohl(*(uint32_t*)ext_ptr));
125  ext_ptr += 4;
126  ext_ptr += 2; // reserved
127  _fec_oti.encoding_symbol_length = ntohs(*(uint16_t*)ext_ptr);
128  ext_ptr += 2;
129  _fec_oti.max_source_block_length = ntohl(*(uint32_t*)ext_ptr);
130  }
131  break;
132  }
133  case EXT_FDT: {
134  uint8_t flute_version = (*ext_ptr & 0xF0) >> 4;
135  if (flute_version > 2) {
136  throw "Unsupported FLUTE version";
137  }
138  _fdt_instance_id = (*ext_ptr & 0x0F) << 16;
139  ext_ptr++;
140  _fdt_instance_id |= ntohs(*(uint16_t*)ext_ptr);
141  break;
142  }
143  case EXT_CENC: {
144  uint8_t encoding = *ext_ptr;
145  switch (encoding) {
146  case 0: _content_encoding = ContentEncoding::NONE; break;
147  case 1: _content_encoding = ContentEncoding::ZLIB; break;
148  case 2: _content_encoding = ContentEncoding::DEFLATE; break;
149  case 3: _content_encoding = ContentEncoding::GZIP; break;
150  }
151  break;
152  }
153  }
154 
155  ext_header_len -= ext_len;
156  hdr_ptr += ext_len;
157  }
158 }
159 
160 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)
161  : _fec_oti(fec_oti)
162 {
163  const size_t max_alc_header_size = 4;
164  auto lct_header_len = 3;
165  if (toi == 0) { // Add extensions for FDT
166  lct_header_len += 5;
167  }
168 
169  auto max_packet_length = max_encoding_symbol_size +
170  lct_header_len * 4
171  + max_alc_header_size ;
172 
173  _buffer = (char*)calloc(max_packet_length, sizeof(char));
174 
175  auto lct_header = (lct_header_t*)_buffer;
176 
177  lct_header->version = 1;
178  lct_header->half_word_flag = 1;
179  lct_header->lct_header_len = lct_header_len;
180  auto hdr_ptr = _buffer + 4;
181  auto payload_ptr = _buffer + 4 * lct_header_len;
182 
183  auto payload_size = EncodingSymbol::to_payload(symbols, payload_ptr, max_encoding_symbol_size + max_alc_header_size, _fec_oti, ContentEncoding::NONE);
184  _len = 4 * lct_header_len + payload_size;
185 
186  hdr_ptr += 4; // CCI = 0
187 
188  *((uint16_t*)hdr_ptr) = htons(tsi);
189  hdr_ptr += 2;
190 
191  *((uint16_t*)hdr_ptr) = htons(toi);
192  hdr_ptr += 2;
193 
194  if (toi == 0) { // Add extensions for FDT
195  *((uint8_t*)hdr_ptr) = EXT_FDT;
196  hdr_ptr += 1;
197  *((uint8_t*)hdr_ptr) = 1 << 4 | (fdt_instance_id & 0x000F0000) >> 16;
198  hdr_ptr += 1;
199  *((uint16_t*)hdr_ptr) = htons(fdt_instance_id & 0x0000FFFF);
200  hdr_ptr += 2;
201 
202  *((uint8_t*)hdr_ptr) = EXT_FTI;
203  hdr_ptr += 1;
204  *((uint8_t*)hdr_ptr) = 4; // HEL
205  hdr_ptr += 1;
206  *((uint16_t*)hdr_ptr) = htons((_fec_oti.transfer_length & 0x00FF0000) >> 32);
207  hdr_ptr += 2;
208  *((uint32_t*)hdr_ptr) = htonl(_fec_oti.transfer_length & 0x0000FFFF);
209  hdr_ptr += 4;
210  hdr_ptr += 2; // reserved
211  *((uint16_t*)hdr_ptr) = htons(_fec_oti.encoding_symbol_length);
212  hdr_ptr += 2;
213  *((uint32_t*)hdr_ptr) = htonl(_fec_oti.max_source_block_length);
214  }
215 }
216 
218 {
219  if (_buffer) free(_buffer);
220 }
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:217
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:21
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