summaryrefslogtreecommitdiffstats
path: root/libtransport/src/protocols/rtc/rtc_packet.h
blob: ffbbd78fd21712e56c174a3444ce8af403cb8f6e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
/*
 * Copyright (c) 2021 Cisco and/or its affiliates.
 */

/*        data packet
 *     +-----------------------------------------+
 *     | uint64_t: timestamp                     |
 *     |                                         |
 *     +-----------------------------------------+
 *     | uint32_t: prod rate (bytes per sec)     |
 *     +-----------------------------------------+
 *     | payload                                 |
 *     | ...                                     |
 */

/*        nack packet
 *     +-----------------------------------------+
 *     | uint64_t: timestamp                     |
 *     |                                         |
 *     +-----------------------------------------+
 *     | uint32_t: prod rate (bytes per sec)     |
 *     +-----------------------------------------+
 *     | uint32_t: current seg in production     |
 *     +-----------------------------------------+
 */

/*        aggregated packets
 *    +---------------------------------+
 *    |c| #pkts | len1  | len2  | ....  |
 *    +----------------------------------
 *
 *    +---------------------------------+
 *    |c| #pkts | resv  |     len 1     |
 *    +----------------------------------
 *
 *  aggregated packets header.
 *  header position. just after the data packet header
 *
 *  c: 1 bit: 0 8bit encoding, 1 16bit encoding
 *  #pkts: 7 bits: number of application packets contained
 *  8bits encoding:
 *  lenX: 8 bits: len in bites of packet X
 *  16bits econding:
 *  resv: 8 bits: reserved field (unused)
 *  lenX: 16bits: len in bytes of packet X
 */

#pragma once
#ifndef _WIN32
#include <arpa/inet.h>
#else
#include <hicn/transport/portability/win_portability.h>
#endif

#include <hicn/transport/portability/endianess.h>

#include <cstring>

namespace transport {

namespace protocol {

namespace rtc {

const uint32_t DATA_HEADER_SIZE = 12;  // bytes
                                       // XXX: sizeof(data_packet_t) is 16
                                       // beacuse of padding
const uint32_t NACK_HEADER_SIZE = 16;

struct data_packet_t {
  uint64_t timestamp;
  uint32_t prod_rate;

  inline uint64_t getTimestamp() const {
    return portability::net_to_host(timestamp);
  }
  inline void setTimestamp(uint64_t time) {
    timestamp = portability::host_to_net(time);
  }

  inline uint32_t getProductionRate() const {
    return portability::net_to_host(prod_rate);
  }
  inline void setProductionRate(uint32_t rate) {
    prod_rate = portability::host_to_net(rate);
  }
};

struct nack_packet_t {
  uint64_t timestamp;
  uint32_t prod_rate;
  uint32_t prod_seg;

  inline uint64_t getTimestamp() const {
    return portability::net_to_host(timestamp);
  }
  inline void setTimestamp(uint64_t time) {
    timestamp = portability::host_to_net(time);
  }

  inline uint32_t getProductionRate() const {
    return portability::net_to_host(prod_rate);
  }
  inline void setProductionRate(uint32_t rate) {
    prod_rate = portability::host_to_net(rate);
  }

  inline uint32_t getProductionSegment() const {
    return portability::net_to_host(prod_seg);
  }
  inline void setProductionSegment(uint32_t seg) {
    prod_seg = portability::host_to_net(seg);
  }
};

class AggrPktHeader {
 public:
  // XXX buf always point to the payload after the data header
  AggrPktHeader(uint8_t *buf, uint16_t max_packet_len, uint16_t pkt_number)
      : buf_(buf), pkt_num_(pkt_number) {
    *buf_ = 0;  // reset the first byte to correctly add the header
                // encoding and the packet number
    if (max_packet_len > 0xff) {
      setAggrPktEncoding16bit();
    } else {
      setAggrPktEncoding8bit();
    }
    setAggrPktNUmber(pkt_number);
    header_len_ = computeHeaderLen();
    memset(buf_ + 1, 0, header_len_ - 1);
  }

  // XXX buf always point to the payload after the data header
  AggrPktHeader(uint8_t *buf) : buf_(buf) {
    encoding_ = getAggrPktEncoding();
    pkt_num_ = getAggrPktNumber();
    header_len_ = computeHeaderLen();
  }

  ~AggrPktHeader(){};

  int addPacketToHeader(uint8_t index, uint16_t len) {
    if (index > pkt_num_) return -1;

    setAggrPktLen(index, len);
    return 0;
  }

  int getPointerToPacket(uint8_t index, uint8_t **pkt_ptr, uint16_t *pkt_len) {
    if (index > pkt_num_) return -1;

    uint16_t len = 0;
    for (int i = 0; i < index; i++)
      len += getAggrPktLen(i);  // sum the pkts len from 0 to index - 1

    uint16_t offset = len + header_len_;
    *pkt_ptr = buf_ + offset;
    *pkt_len = getAggrPktLen(index);
    return 0;
  }

  int getPacketOffsets(uint8_t index, uint16_t *pkt_offset, uint16_t *pkt_len) {
    if (index > pkt_num_) return -1;

    uint16_t len = 0;
    for (int i = 0; i < index; i++)
      len += getAggrPktLen(i);  // sum the pkts len from 0 to index - 1

    uint16_t offset = len + header_len_;
    *pkt_offset = offset;
    *pkt_len = getAggrPktLen(index);

    return 0;
  }

  uint8_t *getPayloadAppendPtr() { return buf_ + header_len_; }

  uint16_t getHeaderLen() { return header_len_; }

  uint8_t getNumberOfPackets() { return pkt_num_; }

 private:
  inline uint16_t computeHeaderLen() const {
    uint16_t len = 4;  // min len in bytes
    if (!encoding_) {
      while (pkt_num_ >= len) {
        len += 4;
      }
    } else {
      while (pkt_num_ * 2 >= len) {
        len += 4;
      }
    }
    return len;
  }

  inline uint8_t getAggrPktEncoding() const {
    // get the first bit of the first byte
    return (*buf_ >> 7);
  }

  inline void setAggrPktEncoding8bit() {
    // reset the first bit of the first byte
    encoding_ = 0;
    *buf_ &= 0x7f;
  }

  inline void setAggrPktEncoding16bit() {
    // set the first bit of the first byte
    encoding_ = 1;
    *buf_ ^= 0x80;
  }

  inline uint8_t getAggrPktNumber() const {
    // return the first byte with the first bit = 0
    return (*buf_ & 0x7f);
  }

  inline void setAggrPktNUmber(uint8_t val) {
    // set the val without modifying the first bit
    *buf_ &= 0x80;  // reset everithing but the first bit
    val &= 0x7f;    // reset the first bit
    *buf_ |= val;   // or the vals, done!
  }

  inline uint16_t getAggrPktLen(uint8_t pkt_index) const {
    pkt_index++;
    if (!encoding_) {  // 8 bits
      return (uint16_t) * (buf_ + pkt_index);
    } else {  // 16 bits
      uint16_t *buf_16 = (uint16_t *)buf_;
      return portability::net_to_host(*(buf_16 + pkt_index));
    }
  }

  inline void setAggrPktLen(uint8_t pkt_index, uint16_t len) {
    pkt_index++;
    if (!encoding_) {  // 8 bits
      *(buf_ + pkt_index) = (uint8_t)len;
    } else {  // 16 bits
      uint16_t *buf_16 = (uint16_t *)buf_;
      *(buf_16 + pkt_index) = portability::host_to_net(len);
    }
  }

  uint8_t *buf_;
  uint8_t encoding_;
  uint8_t pkt_num_;
  uint16_t header_len_;
};

}  // end namespace rtc

}  // end namespace protocol

}  // end namespace transport