tcp refactoring

This commit is contained in:
cozis
2023-08-29 14:22:52 +02:00
parent 91f2526f15
commit 3489f62140
6 changed files with 114 additions and 79 deletions
+4 -2
View File
@@ -16,12 +16,14 @@ static_assert(sizeof(ip_address_t) == 4);
#define MAC_BROADCAST (mac_address_t) {.data = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}} #define MAC_BROADCAST (mac_address_t) {.data = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}
typedef struct { typedef struct {
const void *src; const void *ptr;
size_t len; size_t len;
} slice_list_t; } slice_t;
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) #define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
#define MAX(X, Y) ((X) > (Y) ? (X) : (Y)) #define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
#define ABS(X) ((X) < 0 ? -(X) : (X)) #define ABS(X) ((X) < 0 ? -(X) : (X))
#define COUNT(X) ((int) (sizeof(X) / sizeof((X)[0])))
#define SLICE(X) ((slice_t) {.ptr=&(X), .len=sizeof(X)})
#endif /* MICROTCP_DEFS_H */ #endif /* MICROTCP_DEFS_H */
+4 -6
View File
@@ -134,14 +134,12 @@ int ip_send(ip_state_t *state, ip_protocol_t protocol,
ip_address_t dst, bool no_fragm, ip_address_t dst, bool no_fragm,
const void *src, size_t len) const void *src, size_t len)
{ {
const slice_list_t slices[] = { const slice_t slices[] = {{src, len}};
{src, len} return ip_send_2(state, protocol, dst, no_fragm, slices, COUNT(slices));
};
return ip_send_2(state, protocol, dst, no_fragm, slices, 1);
} }
int ip_send_2(ip_state_t *state, ip_protocol_t protocol, ip_address_t dst, int ip_send_2(ip_state_t *state, ip_protocol_t protocol, ip_address_t dst,
bool no_fragm, const slice_list_t *slices, size_t num_slices) bool no_fragm, const slice_t *slices, size_t num_slices)
{ {
size_t total_len = 0; size_t total_len = 0;
for (size_t i = 0; i < num_slices; i++) for (size_t i = 0; i < num_slices; i++)
@@ -197,7 +195,7 @@ int ip_send_2(ip_state_t *state, ip_protocol_t protocol, ip_address_t dst,
size_t copied_slices = 0; size_t copied_slices = 0;
while (copied_bytes < considered_payload) { while (copied_bytes < considered_payload) {
size_t copying = MIN(slices[copied_slices].len, considered_payload - copied_bytes); size_t copying = MIN(slices[copied_slices].len, considered_payload - copied_bytes);
memcpy(packet->payload + copied_bytes, slices[copied_slices].src, copying); memcpy(packet->payload + copied_bytes, slices[copied_slices].ptr, copying);
copied_bytes += copying; copied_bytes += copying;
copied_slices++; copied_slices++;
} }
+1 -1
View File
@@ -59,6 +59,6 @@ void ip_change_output_buffer(ip_state_t *state, void *ptr, size_t max);
void ip_init(ip_state_t *state, ip_address_t ip, void *send_data, void (*send)(void*, ip_address_t, size_t)); void ip_init(ip_state_t *state, ip_address_t ip, void *send_data, void (*send)(void*, ip_address_t, size_t));
void ip_free(ip_state_t *state); void ip_free(ip_state_t *state);
int ip_send(ip_state_t *state, ip_protocol_t protocol, ip_address_t dst, bool no_fragm, const void *src, size_t len); int ip_send(ip_state_t *state, ip_protocol_t protocol, ip_address_t dst, bool no_fragm, const void *src, size_t len);
int ip_send_2(ip_state_t *state, ip_protocol_t protocol, ip_address_t dst, bool no_fragm, const slice_list_t *slices, size_t num_slices); int ip_send_2(ip_state_t *state, ip_protocol_t protocol, ip_address_t dst, bool no_fragm, const slice_t *slices, size_t num_slices);
void ip_process_packet(ip_state_t *state, const void *packet, size_t len); void ip_process_packet(ip_state_t *state, const void *packet, size_t len);
bool ip_plug_protocol(ip_state_t *ip_state, uint8_t protocol, void *data, void (*process_packet)(void *data, ip_address_t sender, const void *packet, size_t len)); bool ip_plug_protocol(ip_state_t *ip_state, uint8_t protocol, void *data, void (*process_packet)(void *data, ip_address_t sender, const void *packet, size_t len));
+1 -2
View File
@@ -197,7 +197,7 @@ static void send_arp_packet(void *data, mac_address_t dst)
} }
static int send_tcp_segment(void *data, ip_address_t ip, static int send_tcp_segment(void *data, ip_address_t ip,
const slice_list_t *slices, const slice_t *slices,
size_t num_slices) size_t num_slices)
{ {
microtcp_t *mtcp = data; microtcp_t *mtcp = data;
@@ -416,7 +416,6 @@ void microtcp_step(microtcp_t *mtcp)
return; return;
uint64_t current_time_ms = get_time_in_ms(); uint64_t current_time_ms = get_time_in_ms();
fprintf(stderr, "current_time_ms=%lld\n", current_time_ms);
LOCK_WHEN_THREADED(mtcp); LOCK_WHEN_THREADED(mtcp);
{ {
+102 -66
View File
@@ -128,20 +128,20 @@ typedef struct {
uint8_t reserved; uint8_t reserved;
uint8_t protocol; uint8_t protocol;
uint16_t tcp_length; uint16_t tcp_length;
} tcp_pseudoheader_t; } tcp_pseudoheader_t; // Ensure packed?
static uint16_t static uint16_t
calculate_checksum(const slice_list_t *slices, size_t num_slices) calculate_byte_checksum(const slice_t *slices, size_t num_slices)
{ {
uint32_t sum = 0xffff; uint32_t sum = 0xffff;
for (size_t slice_idx = 0; slice_idx < num_slices; slice_idx++) { for (size_t slice_idx = 0; slice_idx < num_slices; slice_idx++) {
const uint16_t *src = slices[slice_idx].src; const uint16_t *ptr = slices[slice_idx].ptr;
const size_t len = slices[slice_idx].len; const size_t len = slices[slice_idx].len;
for (size_t i = 0; i < len/2; i++) { for (size_t i = 0; i < len/2; i++) {
sum += net_to_cpu_u16(src[i]); sum += net_to_cpu_u16(ptr[i]);
if (sum > 0xffff) if (sum > 0xffff)
sum -= 0xffff; sum -= 0xffff;
} }
@@ -149,7 +149,7 @@ calculate_checksum(const slice_list_t *slices, size_t num_slices)
if (len & 1) { if (len & 1) {
alignas(uint16_t) uint8_t temp[2]; alignas(uint16_t) uint8_t temp[2];
temp[0] = ((uint8_t*) slices[slice_idx].src)[len-1]; temp[0] = ((uint8_t*) slices[slice_idx].ptr)[len-1];
temp[1] = 0; temp[1] = 0;
uint16_t temp2 = *(uint16_t*) temp; uint16_t temp2 = *(uint16_t*) temp;
@@ -162,77 +162,116 @@ calculate_checksum(const slice_list_t *slices, size_t num_slices)
return cpu_to_net_u16(~sum); return cpu_to_net_u16(~sum);
} }
static void emit_segment(tcp_connection_t *connection, uint8_t flags, size_t payload) static tcp_segment_t
compile_segment(uint32_t wnd, uint8_t flags,
uint16_t sport, uint16_t dport,
uint32_t seq_no, uint32_t ack_no)
{ {
tcp_listener_t *listener = connection->listener; tcp_segment_t header;
tcp_state_t *state = listener->state; //memset(header, 0, sizeof(tcp_segment_t));
int offset = 5; // No options
header.src_port = cpu_to_net_u16(sport);
header.dst_port = cpu_to_net_u16(dport);
header.flags = flags;
header.seq_no = cpu_to_net_u32(seq_no);
header.ack_no = cpu_to_net_u32(ack_no);
header.offset1 = cpu_is_little_endian() ? 0 : offset;
header.offset2 = cpu_is_little_endian() ? offset : 0;
header.window = cpu_to_net_u16(wnd); // Why is a 32 bit integer being backed into a 16 bit?
header.checksum = 0; // Will be calculated later
header.urgent_pointer = 0;
return header;
}
static uint16_t
calculate_header_checksum(tcp_segment_t header, slice_t data,
ip_address_t self_ip, ip_address_t peer_ip)
{
tcp_pseudoheader_t pseudo;
pseudo.src_addr = self_ip;
pseudo.dst_addr = peer_ip;
pseudo.reserved = 0;
pseudo.protocol = 6; // TCP
pseudo.tcp_length = cpu_to_net_u16(sizeof(tcp_segment_t) + data.len);
slice_t list[] = { SLICE(pseudo), SLICE(header), data };
return calculate_byte_checksum(list, COUNT(list));
}
static void
compile_checksum(tcp_segment_t *header, slice_t data,
ip_address_t self_ip, ip_address_t peer_ip)
{
header->checksum = calculate_header_checksum(*header, data, self_ip, peer_ip);
}
static int
emit_segment_bytes(tcp_state_t *tcp, ip_address_t ip,
tcp_segment_t header, slice_t data)
{
slice_t slices[] = { SLICE(header), data };
return tcp->callbacks.send(tcp->callbacks.data, ip, slices, COUNT(slices));
}
static slice_t
get_pending_output_data(tcp_connection_t *c, size_t max)
{
slice_t s;
// [snd_wnd + snd_una - snd_nxt] is the number of bytes that // [snd_wnd + snd_una - snd_nxt] is the number of bytes that
// are in the output buffer but weren't sent yet // are in the output buffer but weren't sent yet
size_t payload_being_sent = MIN(payload, connection->snd_wnd + connection->snd_una - connection->snd_nxt); s.ptr = c->out_buffer + c->snd_nxt - c->snd_una;
size_t total_segment_size = sizeof(tcp_segment_t) + payload_being_sent; s.len = MIN(max, c->snd_wnd + c->snd_una - c->snd_nxt);
return s;
}
uint32_t ack_no = 0; // Send a tcp segment on the connection
if (flags & TCP_FLAG_ACK) // with a maximum payload of "payload" and
ack_no = connection->rcv_nxt; // the specified flags.
static void
emit_segment(tcp_connection_t *c, uint8_t flags, size_t max_payload)
{
tcp_listener_t *listener = c->listener;
tcp_state_t *state = listener->state;
uint32_t seq_no = connection->snd_nxt; slice_t data = get_pending_output_data(c, max_payload);
int offset = 5; // No options uint16_t sport = listener->port;
tcp_segment_t header = { uint16_t dport = c->peer_port;
.src_port = cpu_to_net_u16(listener->port), uint32_t ack_no = (flags & TCP_FLAG_ACK) ? c->rcv_nxt : 0;
.dst_port = cpu_to_net_u16(connection->peer_port), uint32_t seq_no = c->snd_nxt;
.flags = flags,
.seq_no = cpu_to_net_u32(seq_no),
.ack_no = cpu_to_net_u32(ack_no),
.offset1 = cpu_is_little_endian() ? 0 : offset,
.offset2 = cpu_is_little_endian() ? offset : 0,
.window = cpu_to_net_u16(connection->rcv_wnd), // Why is a 32 bit integer being backed into a 16 bit?
.checksum = 0, // Will be calculated later
.urgent_pointer = 0,
};
tcp_pseudoheader_t pseudo_header = { ip_address_t self_ip = state->ip;
.src_addr = state->ip, ip_address_t peer_ip = c->peer_ip;
.dst_addr = connection->peer_ip,
.reserved = 0,
.protocol = 6, // TCP
.tcp_length = cpu_to_net_u16(total_segment_size),
};
const void *send_ptr = connection->out_buffer + connection->snd_nxt - connection->snd_una; tcp_segment_t header = compile_segment(c->rcv_wnd, flags, sport, dport, seq_no, ack_no);
size_t send_len = payload_being_sent; compile_checksum(&header, data, self_ip, peer_ip);
int result = emit_segment_bytes(state, peer_ip, header, data);
header.checksum = calculate_checksum((slice_list_t[]) { if (result < 0)
{&pseudo_header, sizeof(tcp_pseudoheader_t)}, return; // It wasn't possible to send out bytes.
{&header, sizeof(tcp_segment_t)}, // We'll try again later!
{send_ptr, send_len},
}, 3);
int result = state->callbacks.send(state->callbacks.data, connection->peer_ip, (slice_list_t[]) { if (result < (int) sizeof(tcp_segment_t)) { // What about options??
{&header, sizeof(tcp_segment_t)}, // Not even the TCP header was sent.
{send_ptr, send_len}, // I hope this nexer happens!
}, 2); assert(0);
return;
if (result < 0) {
// It wasn't possible to send out bytes. We'll try again later!
} else {
size_t actually_sent_bytes = (size_t) result;
if (actually_sent_bytes < sizeof(tcp_segment_t)) { // What about options??
// Not even the TCP header was sent. I hope this
// doesn't ever happen!
assert(0);
} else {
size_t actually_sent_payload_bytes = actually_sent_bytes - sizeof(tcp_segment_t);
connection->snd_nxt += actually_sent_payload_bytes;
}
} }
if (!connection->calculating_rtt) { c->snd_nxt += result - sizeof(tcp_segment_t);
connection->calculating_rtt = true;
connection->rtt_calc_seq = connection->snd_nxt; // -1? // Increment for ghost bytes
connection->rtt_calc_time = connection->listener->state->timers.current_time_ms; if (flags & TCP_FLAG_SYN) c->snd_nxt++;
if (flags & TCP_FLAG_FIN) c->snd_nxt++;
if (c->calculating_rtt == false && seq_no < c->snd_nxt) {
c->calculating_rtt = true;
c->rtt_calc_seq = seq_no;
c->rtt_calc_time = c->listener->state->timers.current_time_ms;
} }
} }
@@ -546,7 +585,6 @@ void tcp_process_segment(tcp_state_t *state, ip_address_t sender,
// Instead of incrementing the snd_una for the SYN we just send, // Instead of incrementing the snd_una for the SYN we just send,
// we'll ignore it and also ignore it when the respective ACK si // we'll ignore it and also ignore it when the respective ACK si
// received. // received.
connection->snd_nxt++;
TCP_DEBUG_LOG("Connection request handled"); TCP_DEBUG_LOG("Connection request handled");
@@ -865,14 +903,12 @@ void tcp_connection_destroy(tcp_connection_t *connection)
case TCP_STATE_ESTAB: case TCP_STATE_ESTAB:
TCP_DEBUG_LOG("ESTAB -> FIN-WAIT-1"); TCP_DEBUG_LOG("ESTAB -> FIN-WAIT-1");
emit_segment(connection, TCP_FLAG_FIN | TCP_FLAG_ACK, 0); emit_segment(connection, TCP_FLAG_FIN | TCP_FLAG_ACK, 0);
connection->snd_nxt++; // FIN ghost byte
connection->state = TCP_STATE_FIN_WAIT_1; connection->state = TCP_STATE_FIN_WAIT_1;
break; break;
case TCP_STATE_CLOSE_WAIT: case TCP_STATE_CLOSE_WAIT:
TCP_DEBUG_LOG("ESTAB -> LAST-ACK"); TCP_DEBUG_LOG("ESTAB -> LAST-ACK");
emit_segment(connection, TCP_FLAG_FIN | TCP_FLAG_ACK, 0); emit_segment(connection, TCP_FLAG_FIN | TCP_FLAG_ACK, 0);
connection->snd_nxt++; // FIN ghost byte
connection->state = TCP_STATE_LAST_ACK; connection->state = TCP_STATE_LAST_ACK;
break; break;
+1 -1
View File
@@ -152,7 +152,7 @@ struct tcp_connection_t {
typedef struct { typedef struct {
void *data; void *data;
int (*send)(void *data, ip_address_t ip, const slice_list_t *slices, size_t num_slices); int (*send)(void *data, ip_address_t ip, const slice_t *slices, size_t num_slices);
} tcp_callbacks_t; } tcp_callbacks_t;
struct tcp_state_t { struct tcp_state_t {