Skip to content

Commit 2ba4345

Browse files
authored
Merge pull request #1207 from AndreasAakesson/dev
tcp: Finished RFC 7323
2 parents acf2b39 + d375717 commit 2ba4345

12 files changed

Lines changed: 355 additions & 203 deletions

File tree

api/common

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -53,27 +53,11 @@
5353
#undef Expects
5454
#undef Ensures
5555

56-
#define Expects(cond) \
57-
do { \
58-
if (UNLIKELY(not (cond))) { \
59-
std::cerr << "OS: Precondition (" OS_STRINGIFY(cond) \
60-
<< ") failed...\n" << "\t...in function: " \
61-
<< __func__ << " @" << __FILE__ << ":" \
62-
<< __LINE__ << '\n'; \
63-
std::terminate(); \
64-
} \
65-
} while(0)
56+
#define Expects(cond) \
57+
assert(LIKELY(cond) && "OS: Precondition failed")
6658

67-
#define Ensures(cond) \
68-
do { \
69-
if (UNLIKELY(not (cond))) { \
70-
std::cerr << "OS: Postcondition (" OS_STRINGIFY(cond) \
71-
<< ") failed...\n" << "\t...in function: " \
72-
<< __func__ << " @" << __FILE__ << ":" \
73-
<< __LINE__ << '\n'; \
74-
std::terminate(); \
75-
} \
76-
} while(0)
59+
#define Ensures(cond) \
60+
assert(LIKELY(cond) && "OS: Postcondition failed")
7761

7862
#endif //< defined(OS_TERMINATE_ON_CONTRACT_VIOLATION)
7963

api/net/ip4/packet_ip4.hpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,11 @@ namespace net {
8989
protected:
9090
Byte* ip_data() noexcept __attribute__((assume_aligned(4)))
9191
{
92-
Expects((size_t)(data_end() - layer_begin()) >= sizeof(IP4::header));
9392
return layer_begin() + ip_header_length();
9493
}
9594

9695
const Byte* ip_data() const noexcept __attribute__((assume_aligned(4)))
9796
{
98-
Expects((size_t)(data_end() - layer_begin()) >= sizeof(IP4::header));
9997
return layer_begin() + ip_header_length();
10098
}
10199

api/net/tcp/common.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ namespace net {
3838
static constexpr uint16_t default_mss {536};
3939
// the maximum amount of half-open connections per port (listener)
4040
static constexpr size_t default_max_syn_backlog {64};
41+
// clock granularity of the timestamp value clock
42+
static constexpr float clock_granularity {0.0001};
4143

4244
static const std::chrono::seconds default_msl {30};
4345
static const std::chrono::milliseconds default_dack_timeout {40};

api/net/tcp/connection.hpp

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ class Connection : public std::enable_shared_from_this<Connection> {
108108
* Emitted on RTO - When the retransmission timer times out, before retransmitting.
109109
* Gives the current attempt and the current timeout in seconds.
110110
*/
111-
using RtxTimeoutCallback = delegate<void(size_t no_attempts, double rto)>;
111+
using RtxTimeoutCallback = delegate<void(size_t no_attempts, std::chrono::milliseconds rto)>;
112112
inline Connection& on_rtx_timeout(RtxTimeoutCallback);
113113

114114

@@ -668,7 +668,7 @@ class Connection : public std::enable_shared_from_this<Connection> {
668668
{ if(on_packet_dropped_) on_packet_dropped_(packet, reason); }
669669

670670
void signal_rtx_timeout()
671-
{ if(on_rtx_timeout_) on_rtx_timeout_(rtx_attempt_+1, rttm.RTO); }
671+
{ if(on_rtx_timeout_) on_rtx_timeout_(rtx_attempt_+1, rttm.rto_ms()); }
672672

673673
/*
674674
Drop a packet. Used for debug/callback.
@@ -830,6 +830,15 @@ class Connection : public std::enable_shared_from_this<Connection> {
830830
*/
831831
void retransmit();
832832

833+
/**
834+
* @brief Take an RTT measurment from an incoming packet.
835+
* Uses timestamp if timestamp options are in use,
836+
* else RTTM start/stop.
837+
*
838+
* @param[in] <unnamed> An incomming TCP packet
839+
*/
840+
void take_rtt_measure(const Packet&);
841+
833842
/*
834843
Start retransmission timer.
835844
*/
@@ -917,13 +926,22 @@ class Connection : public std::enable_shared_from_this<Connection> {
917926
/*
918927
Parse and apply options.
919928
*/
920-
void parse_options(Packet&);
929+
void parse_options(const Packet&);
921930

922931
/*
923932
Add an option.
924933
*/
925934
void add_option(Option::Kind, Packet&);
926935

936+
/**
937+
* @brief Parses the timestamp option from a packet (if any).
938+
* Assumes the packet contains no other options.
939+
*
940+
* @param[in] <unnamed> A TCP packet
941+
*
942+
* @return A pointer the the timestamp option (nullptr if none)
943+
*/
944+
Option::opt_ts* parse_ts_option(const Packet&) const;
927945

928946
}; // < class Connection
929947

api/net/tcp/options.hpp

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ struct Option {
3131

3232
enum Kind {
3333
END = 0x00, // End of option list
34-
NOP = 0x01, // No-Opeartion
34+
NOP = 0x01, // No-Operation
3535
MSS = 0x02, // Maximum Segment Size [RFC 793] Rev: [879, 6691]
3636
WS = 0x03, // Window Scaling [RFC 7323] p. 8
3737
TS = 0x08, // Timestamp [RFC 7323] p. 11
@@ -41,6 +41,9 @@ struct Option {
4141
const uint8_t length {0};
4242
uint8_t data[0];
4343

44+
std::string kind_string() const
45+
{ return kind_string(static_cast<Kind>(kind)); }
46+
4447
static std::string kind_string(Kind kind) {
4548
switch(kind) {
4649
case MSS:
@@ -52,11 +55,20 @@ struct Option {
5255
case TS:
5356
return {"Timestamp"};
5457

58+
case NOP:
59+
return {"No-Operation"};
60+
61+
case END:
62+
return {"End of list"};
63+
5564
default:
5665
return {"Unknown Option"};
5766
}
5867
}
5968

69+
/**
70+
* @brief Maximum Segment Size option [RFC 793]
71+
*/
6072
struct opt_mss {
6173
const uint8_t kind {MSS};
6274
const uint8_t length {4};
@@ -80,6 +92,9 @@ struct Option {
8092

8193
} __attribute__((packed));
8294

95+
/**
96+
* @brief Timestamp option [RFC 7323] p. 11
97+
*/
8398
struct opt_ts {
8499
const uint8_t kind {TS};
85100
const uint8_t length {10};
@@ -93,6 +108,32 @@ struct Option {
93108

94109
} __attribute__((packed));
95110

111+
/**
112+
* @brief An aligned version of a Timestamp option. Includes padding,
113+
* making the ts values on word boundaries.
114+
*
115+
The following layout is recommended for sending options on
116+
non-<SYN> segments to achieve maximum feasible alignment of 32-bit
117+
and 64-bit machines.
118+
119+
+--------+--------+--------+--------+
120+
| NOP | NOP | TSopt | 10 |
121+
+--------+--------+--------+--------+
122+
| TSval timestamp |
123+
+--------+--------+--------+--------+
124+
| TSecr timestamp |
125+
+--------+--------+--------+--------+
126+
*/
127+
struct opt_ts_align {
128+
const uint8_t padding[2] {NOP, NOP};
129+
const opt_ts ts;
130+
131+
opt_ts_align(const uint32_t val, const uint32_t echo)
132+
: ts{val, echo}
133+
{}
134+
135+
} __attribute__((packed));
136+
96137
}; // < struct Option
97138

98139
} // < namespace net

api/net/tcp/packet.hpp

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -186,33 +186,73 @@ class Packet : public PacketIP4 {
186186
inline Byte* tcp_data()
187187
{ return ip_data() + tcp_header_length(); }
188188

189+
inline const Byte* tcp_data() const
190+
{ return ip_data() + tcp_header_length(); }
191+
189192
// Length of data in packet when header has been accounted for
190193
inline uint16_t tcp_data_length() const
191194
{ return ip_data_length() - tcp_header_length(); }
192195

193196
inline bool has_tcp_data() const
194197
{ return tcp_data_length() > 0; }
195198

196-
template <typename T, typename... Args>
199+
/**
200+
* @brief Adds a tcp option.
201+
*
202+
* @todo It's probably a better idea to make the option include
203+
* the padding for it to be aligned, and avoid two mem operations
204+
*
205+
* @tparam T TCP Option
206+
* @tparam Padding padding in bytes to be put infront of the option
207+
* @tparam Args construction args to option T
208+
*/
209+
template <typename T, int Padding = 0, typename... Args>
197210
inline void add_tcp_option(Args&&... args) {
198211
// to avoid headache, options need to be added BEFORE any data.
199212
assert(!has_tcp_data());
213+
struct NOP {
214+
uint8_t kind{0x01};
215+
};
200216
// option address
201217
auto* addr = tcp_options()+tcp_options_length();
202-
// emplace the option
203-
const auto& opt = *(new (addr) T(args...));
218+
// if to use pre padding
219+
if(Padding)
220+
new (addr) NOP[Padding];
221+
222+
// emplace the option after pre padding
223+
const auto& opt = *(new (addr + Padding) T(args...));
204224

205225
// find number of NOP to pad with
206-
const auto nops = opt.length % 4;
226+
const auto nops = (opt.length + Padding) % 4;
207227
if(nops) {
208-
struct NOP {
209-
uint8_t kind{0x01};
210-
};
211-
new (addr + opt.length) NOP[nops];
228+
new (addr + Padding + opt.length) NOP[nops];
212229
}
213230

214231
// update offset
215-
set_offset(offset() + round_up(opt.length, 4));
232+
set_offset(offset() + round_up(opt.length + Padding, 4));
233+
234+
set_length(); // update
235+
}
236+
237+
/**
238+
* @brief Adds a tcp option aligned.
239+
* Assumes the user knows what he's doing.
240+
*
241+
* @tparam T An aligned TCP option
242+
* @tparam Args construction args to option T
243+
*/
244+
template <typename T, typename... Args>
245+
inline void add_tcp_option_aligned(Args&&... args) {
246+
// to avoid headache, options need to be added BEFORE any data.
247+
Expects(!has_tcp_data() and sizeof(T) % 4 == 0);
248+
249+
// option address
250+
auto* addr = tcp_options()+tcp_options_length();
251+
// emplace the option
252+
new (addr) T(args...);
253+
254+
// update offset
255+
set_offset(offset() + (sizeof(T) / 4));
216256

217257
set_length(); // update
218258
}
@@ -228,6 +268,9 @@ class Packet : public PacketIP4 {
228268
inline uint8_t* tcp_options()
229269
{ return (uint8_t*) tcp_header().options; }
230270

271+
inline const uint8_t* tcp_options() const
272+
{ return (const uint8_t*) tcp_header().options; }
273+
231274
inline uint8_t tcp_options_length() const
232275
{ return tcp_header_length() - sizeof(Header); }
233276

0 commit comments

Comments
 (0)