the TAP IP was the same as the microtcp instance, which wasn't right. Now the TAP is at 10.0.0.5 and the TCP at 10.0.0.4; fixed some bugs in the TCP state machine and made it so it always ACKs; fixed TCP checksum calculation
This commit is contained in:
@@ -47,4 +47,8 @@ int main(void)
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
The build result is a header and a .c obtained as an amalgamation of all the source files. Any header included in the source files must be guarded by a `#ifndef MICROTCP_AMALGAMATION`.
|
The build result is a header and a .c obtained as an amalgamation of all the source files. Any header included in the source files must be guarded by a `#ifndef MICROTCP_AMALGAMATION`.
|
||||||
|
|
||||||
|
## Functionalities
|
||||||
|
MicroTCP will not support
|
||||||
|
* TCP options
|
||||||
@@ -55,7 +55,7 @@ int main(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
tuntap_set_ip(dev, ip, netmask);
|
tuntap_set_ip(dev, "10.0.0.5", netmask);
|
||||||
tuntap_set_hwaddr(dev, mac);
|
tuntap_set_hwaddr(dev, mac);
|
||||||
|
|
||||||
if (tuntap_up(dev)) {
|
if (tuntap_up(dev)) {
|
||||||
|
|||||||
@@ -135,6 +135,7 @@ struct conn_t {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool exiting;
|
bool exiting;
|
||||||
|
microtcp_t *mtcp;
|
||||||
microtcp_socket_t *sock;
|
microtcp_socket_t *sock;
|
||||||
microtcp_mux_t *mux;
|
microtcp_mux_t *mux;
|
||||||
int connum;
|
int connum;
|
||||||
@@ -1416,6 +1417,7 @@ static const char *init(context_t *context, unsigned short port,
|
|||||||
microtcp_t *mtcp = microtcp_create_using_callbacks(config.ip, config.mac, callbacks);
|
microtcp_t *mtcp = microtcp_create_using_callbacks(config.ip, config.mac, callbacks);
|
||||||
if (!mtcp)
|
if (!mtcp)
|
||||||
return "Failed to initialize TCP";
|
return "Failed to initialize TCP";
|
||||||
|
context->mtcp = mtcp;
|
||||||
|
|
||||||
microtcp_errcode_t errcode;
|
microtcp_errcode_t errcode;
|
||||||
|
|
||||||
@@ -1469,6 +1471,8 @@ const char *xhttp(unsigned short port, xh_callback callback,
|
|||||||
|
|
||||||
while(!context.exiting)
|
while(!context.exiting)
|
||||||
{
|
{
|
||||||
|
microtcp_step(context.mtcp);
|
||||||
|
|
||||||
microtcp_muxevent_t ev;
|
microtcp_muxevent_t ev;
|
||||||
if (!microtcp_mux_wait(context.mux, &ev))
|
if (!microtcp_mux_wait(context.mux, &ev))
|
||||||
continue;
|
continue;
|
||||||
@@ -1492,7 +1496,7 @@ const char *xhttp(unsigned short port, xh_callback callback,
|
|||||||
if(ev.userp == NULL)
|
if(ev.userp == NULL)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
fprintf(stderr, "XHTTP :: New connection\n");
|
fprintf(stderr, "XHTTP :: New connection\n");
|
||||||
#endif
|
#endif
|
||||||
// New connection.
|
// New connection.
|
||||||
conn_t *newly_accepted = accept_connection(&context);
|
conn_t *newly_accepted = accept_connection(&context);
|
||||||
@@ -1559,6 +1563,7 @@ const char *xhttp(unsigned short port, xh_callback callback,
|
|||||||
|
|
||||||
(void) microtcp_close(context.sock);
|
(void) microtcp_close(context.sock);
|
||||||
(void) microtcp_mux_destroy(context.mux);
|
(void) microtcp_mux_destroy(context.mux);
|
||||||
|
microtcp_destroy(context.mtcp);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ MEMDBG=valgrind
|
|||||||
LIBDIR = 3p/lib
|
LIBDIR = 3p/lib
|
||||||
INCDIR = 3p/include
|
INCDIR = 3p/include
|
||||||
|
|
||||||
CFLAGS = $(CFLAGS_PLATFORM) -I$(INCDIR) -Ibuild/ -Wall -Wextra -DDEBUG=1 -DARP_DEBUG -DMICROTCP_DEBUG -DIP_DEBUG -DICMP_DEBUG -DTCP_DEBUG -DMICROTCP_BACKGROUND_THREAD -DMICROTCP_USING_TAP -DMICROTCP_USING_MUX
|
CFLAGS = $(CFLAGS_PLATFORM) -I$(INCDIR) -Ibuild/ -Wall -Wextra
|
||||||
LFLAGS = -ltuntap $(LFLAGS_PLATFORM) -L$(LIBDIR)
|
LFLAGS = -ltuntap $(LFLAGS_PLATFORM) -L$(LIBDIR)
|
||||||
|
|
||||||
ifeq ($(MEMDBG),drmemory)
|
ifeq ($(MEMDBG),drmemory)
|
||||||
@@ -89,7 +89,7 @@ all: build/microtcp.h build/microtcp.c build/echo_tcp build/echo_http
|
|||||||
|
|
||||||
build/echo_tcp: examples/echo_tcp.c $(LIBDIR)/libtuntap.a 3p/include/tuntap.h 3p/include/tuntap-export.h build/microtcp.c build/microtcp.h
|
build/echo_tcp: examples/echo_tcp.c $(LIBDIR)/libtuntap.a 3p/include/tuntap.h 3p/include/tuntap-export.h build/microtcp.c build/microtcp.h
|
||||||
mkdir -p $(@D)
|
mkdir -p $(@D)
|
||||||
gcc build/microtcp.c examples/echo_tcp.c -o $@ $(CFLAGS) $(LFLAGS)
|
gcc build/microtcp.c examples/echo_tcp.c -o $@ $(CFLAGS) $(LFLAGS) -DDEBUG=1 -DARP_DEBUG -DMICROTCP_DEBUG -DIP_DEBUG -DICMP_DEBUG -DTCP_DEBUG -DMICROTCP_BACKGROUND_THREAD -DMICROTCP_USING_TAP -DMICROTCP_USING_MUX
|
||||||
|
|
||||||
build/microtcp.h: src/microtcp.h
|
build/microtcp.h: src/microtcp.h
|
||||||
mkdir -p $(@D)
|
mkdir -p $(@D)
|
||||||
@@ -132,8 +132,8 @@ build/microtcp.c: 3p/include/tinycthread.h 3p/src/tinycthread.c $(wildcard src/*
|
|||||||
printf "\n#line 1 \"src/microtcp.c\"\n" >> $@
|
printf "\n#line 1 \"src/microtcp.c\"\n" >> $@
|
||||||
cat src/microtcp.c >> $@
|
cat src/microtcp.c >> $@
|
||||||
|
|
||||||
build/echo_http: $(LIBDIR)/libtuntap.a 3p/include/tuntap.h 3p/include/tuntap-export.h build/microtcp.h build/microtcp.c
|
build/echo_http: examples/microhttp/main.c $(LIBDIR)/libtuntap.a 3p/include/tuntap.h 3p/include/tuntap-export.h build/microtcp.h build/microtcp.c
|
||||||
gcc examples/microhttp/main.c examples/microhttp/xhttp.c build/microtcp.c -o $@ $(CFLAGS) $(LFLAGS)
|
gcc examples/microhttp/main.c examples/microhttp/xhttp.c build/microtcp.c -o $@ $(CFLAGS) $(LFLAGS) -DDEBUG=1 -DARP_DEBUG -DMICROTCP_DEBUG -DIP_DEBUG -DICMP_DEBUG -DTCP_DEBUG -DMICROTCP_USING_MUX
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -fr build
|
rm -fr build
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
from http.server import BaseHTTPRequestHandler, HTTPServer
|
||||||
|
|
||||||
|
class RequestHandler(BaseHTTPRequestHandler):
|
||||||
|
|
||||||
|
def do_GET(self):
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header('Content-type','text/html')
|
||||||
|
self.end_headers()
|
||||||
|
message = "Hello world!"
|
||||||
|
self.wfile.write(bytes(message, "utf8"))
|
||||||
|
return
|
||||||
|
|
||||||
|
addr = ('127.0.0.1', 8080)
|
||||||
|
HTTPServer(addr, RequestHandler).serve_forever()
|
||||||
@@ -206,6 +206,7 @@ int ip_send_2(ip_state_t *state, ip_protocol_t protocol, ip_address_t dst,
|
|||||||
packet->checksum = calculate_checksum_ip((uint16_t*) packet, 4 * header_length);
|
packet->checksum = calculate_checksum_ip((uint16_t*) packet, 4 * header_length);
|
||||||
|
|
||||||
// Sending updates the [state->output_ptr] and [state->output_len]
|
// Sending updates the [state->output_ptr] and [state->output_len]
|
||||||
|
IP_DEBUG_LOG("sending %d", sizeof(ip_packet_t) + considered_payload);
|
||||||
state->send(state->send_data, dst, sizeof(ip_packet_t) + considered_payload);
|
state->send(state->send_data, dst, sizeof(ip_packet_t) + considered_payload);
|
||||||
|
|
||||||
managed_payload += considered_payload;
|
managed_payload += considered_payload;
|
||||||
|
|||||||
@@ -249,6 +249,7 @@ static void mac_resolved(void *data, arp_resolution_status_t status, mac_address
|
|||||||
ethernet_frame_t *frame = (ethernet_frame_t*) buffer->data;
|
ethernet_frame_t *frame = (ethernet_frame_t*) buffer->data;
|
||||||
frame->dst = mac;
|
frame->dst = mac;
|
||||||
|
|
||||||
|
MICROTCP_DEBUG_LOG("sending %d", buffer->used);
|
||||||
int n = mtcp->callbacks.send(mtcp->callbacks.data, buffer->data, buffer->used);
|
int n = mtcp->callbacks.send(mtcp->callbacks.data, buffer->data, buffer->used);
|
||||||
if (n < 0)
|
if (n < 0)
|
||||||
MICROTCP_DEBUG_LOG("Couldn't send (%s)", strerror(errno));
|
MICROTCP_DEBUG_LOG("Couldn't send (%s)", strerror(errno));
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ connection_create(tcp_listener_t *listener,
|
|||||||
|
|
||||||
connection->snd_una = seq_no;
|
connection->snd_una = seq_no;
|
||||||
connection->snd_wnd = 0;
|
connection->snd_wnd = 0;
|
||||||
connection->snd_nxt = 0;
|
connection->snd_nxt = seq_no;
|
||||||
|
|
||||||
connection->prev = NULL;
|
connection->prev = NULL;
|
||||||
connection->next = NULL;
|
connection->next = NULL;
|
||||||
@@ -154,26 +154,21 @@ 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, bool ack, bool syn, size_t payload)
|
static void emit_segment(tcp_connection_t *connection, uint8_t flags, size_t payload)
|
||||||
{
|
{
|
||||||
tcp_listener_t *listener = connection->listener;
|
tcp_listener_t *listener = connection->listener;
|
||||||
tcp_state_t *state = listener->state;
|
tcp_state_t *state = listener->state;
|
||||||
|
|
||||||
size_t payload_being_sent = MIN(payload, connection->snd_wnd);
|
// [snd_wnd + snd_una - snd_nxt] is the number of bytes that
|
||||||
|
// 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);
|
||||||
size_t total_segment_size = sizeof(tcp_segment_t) + payload_being_sent;
|
size_t total_segment_size = sizeof(tcp_segment_t) + payload_being_sent;
|
||||||
|
|
||||||
uint8_t flags = 0;
|
|
||||||
uint32_t ack_no = 0;
|
uint32_t ack_no = 0;
|
||||||
if (ack) {
|
if (flags & TCP_FLAG_ACK)
|
||||||
flags |= TCP_FLAG_ACK;
|
|
||||||
ack_no = connection->rcv_nxt;
|
ack_no = connection->rcv_nxt;
|
||||||
}
|
|
||||||
if (syn)
|
uint32_t seq_no = connection->snd_nxt;
|
||||||
flags |= TCP_FLAG_SYN;
|
|
||||||
|
|
||||||
uint32_t seq_no = connection->snd_una;
|
|
||||||
//if (payload_being_sent > 0)
|
|
||||||
// seq_no++;
|
|
||||||
|
|
||||||
int offset = 5; // No options
|
int offset = 5; // No options
|
||||||
tcp_segment_t header = {
|
tcp_segment_t header = {
|
||||||
@@ -197,15 +192,19 @@ static void emit_segment(tcp_connection_t *connection, bool ack, bool syn, size_
|
|||||||
.tcp_length = cpu_to_net_u16(total_segment_size),
|
.tcp_length = cpu_to_net_u16(total_segment_size),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const void *send_ptr = connection->out_buffer + connection->snd_nxt - connection->snd_una;
|
||||||
|
size_t send_len = payload_being_sent;
|
||||||
|
|
||||||
header.checksum = calculate_checksum((slice_list_t[]) {
|
header.checksum = calculate_checksum((slice_list_t[]) {
|
||||||
{&pseudo_header, sizeof(tcp_pseudoheader_t)},
|
{&pseudo_header, sizeof(tcp_pseudoheader_t)},
|
||||||
{&header, sizeof(tcp_segment_t)},
|
{&header, sizeof(tcp_segment_t)},
|
||||||
{connection->out_buffer, connection->snd_wnd},
|
{send_ptr, send_len},
|
||||||
}, 3);
|
}, 3);
|
||||||
|
|
||||||
|
TCP_DEBUG_LOG("sending %d+%d=%d", sizeof(tcp_segment_t), send_len, sizeof(tcp_segment_t)+send_len);
|
||||||
int result = state->callbacks.send(state->callbacks.data, connection->peer_ip, (slice_list_t[]) {
|
int result = state->callbacks.send(state->callbacks.data, connection->peer_ip, (slice_list_t[]) {
|
||||||
{&header, sizeof(tcp_segment_t)},
|
{&header, sizeof(tcp_segment_t)},
|
||||||
{connection->out_buffer, payload_being_sent},
|
{send_ptr, send_len},
|
||||||
}, 2);
|
}, 2);
|
||||||
|
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
@@ -213,13 +212,13 @@ static void emit_segment(tcp_connection_t *connection, bool ack, bool syn, size_
|
|||||||
} else {
|
} else {
|
||||||
size_t actually_sent_bytes = (size_t) result;
|
size_t actually_sent_bytes = (size_t) result;
|
||||||
|
|
||||||
if (actually_sent_bytes < sizeof(tcp_segment_t)) {
|
if (actually_sent_bytes < sizeof(tcp_segment_t)) { // What about options??
|
||||||
// Not even the TCP header was sent. I hope this
|
// Not even the TCP header was sent. I hope this
|
||||||
// doesn't ever happen!
|
// doesn't ever happen!
|
||||||
assert(0);
|
assert(0);
|
||||||
} else {
|
} else {
|
||||||
size_t actually_sent_payload_bytes = actually_sent_bytes - sizeof(tcp_segment_t);
|
size_t actually_sent_payload_bytes = actually_sent_bytes - sizeof(tcp_segment_t);
|
||||||
connection->snd_nxt = MAX(connection->snd_nxt, connection->snd_una + actually_sent_payload_bytes);
|
connection->snd_nxt += actually_sent_payload_bytes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,7 +235,7 @@ static void handle_received_data(tcp_connection_t *connection,
|
|||||||
connection->rcv_wnd -= considered;
|
connection->rcv_wnd -= considered;
|
||||||
connection->rcv_nxt += considered;
|
connection->rcv_nxt += considered;
|
||||||
|
|
||||||
emit_segment(connection, true, false, SIZE_MAX);
|
emit_segment(connection, TCP_FLAG_ACK, SIZE_MAX);
|
||||||
|
|
||||||
TCP_DEBUG_LOG("Received %d bytes", considered);
|
TCP_DEBUG_LOG("Received %d bytes", considered);
|
||||||
|
|
||||||
@@ -398,8 +397,11 @@ void tcp_process_segment(tcp_state_t *state, ip_address_t sender,
|
|||||||
}
|
}
|
||||||
connection->state = TCP_STATE_SYN_RCVD;
|
connection->state = TCP_STATE_SYN_RCVD;
|
||||||
|
|
||||||
emit_segment(connection, true, true, 0);
|
emit_segment(connection, TCP_FLAG_SYN | TCP_FLAG_ACK, 0);
|
||||||
connection->snd_una++;
|
// 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
|
||||||
|
// received.
|
||||||
|
connection->snd_nxt++;
|
||||||
|
|
||||||
TCP_DEBUG_LOG("Connection request handled");
|
TCP_DEBUG_LOG("Connection request handled");
|
||||||
|
|
||||||
@@ -443,7 +445,9 @@ void tcp_process_segment(tcp_state_t *state, ip_address_t sender,
|
|||||||
"the SYN we sent. This is valid TCP but we don't support "
|
"the SYN we sent. This is valid TCP but we don't support "
|
||||||
"this case yet. We'll just ignore the data. Hopefully "
|
"this case yet. We'll just ignore the data. Hopefully "
|
||||||
"the peer will retransmit it");
|
"the peer will retransmit it");
|
||||||
|
|
||||||
// The connection is now established.
|
// The connection is now established.
|
||||||
|
connection->snd_una = net_to_cpu_u32(segment->ack_no);
|
||||||
connection->state = TCP_STATE_ESTAB;
|
connection->state = TCP_STATE_ESTAB;
|
||||||
|
|
||||||
move_from_non_established_list_to_non_accepted_queue(connection);
|
move_from_non_established_list_to_non_accepted_queue(connection);
|
||||||
@@ -485,18 +489,36 @@ void tcp_process_segment(tcp_state_t *state, ip_address_t sender,
|
|||||||
if (segment->flags & TCP_FLAG_FIN) {
|
if (segment->flags & TCP_FLAG_FIN) {
|
||||||
|
|
||||||
// Send ACK for the FIN
|
// Send ACK for the FIN
|
||||||
emit_segment(connection, true, false, 0);
|
emit_segment(connection, TCP_FLAG_ACK, 0);
|
||||||
connection->snd_una++; // emit_segment doesn't increment the "snd_una" for ghost bytes
|
|
||||||
|
|
||||||
connection->state = TCP_STATE_CLOSE_WAIT;
|
connection->state = TCP_STATE_CLOSE_WAIT;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TCP_STATE_FIN_WAIT_1:break;
|
case TCP_STATE_FIN_WAIT_1:
|
||||||
|
{
|
||||||
|
// The FIN segment was sent after the user called "close".
|
||||||
|
// In this state we're expecting the ACK flag for the fin.
|
||||||
|
// The same message could also contain the peer's FIN.
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case TCP_STATE_FIN_WAIT_2:break;
|
case TCP_STATE_FIN_WAIT_2:break;
|
||||||
case TCP_STATE_CLOSE_WAIT:break;
|
case TCP_STATE_CLOSE_WAIT:break;
|
||||||
case TCP_STATE_LAST_ACK:break;
|
case TCP_STATE_LAST_ACK:break;
|
||||||
case TCP_STATE_TIME_WAIT:break;
|
case TCP_STATE_TIME_WAIT:
|
||||||
|
{
|
||||||
|
// Pop connection from the accepted_list
|
||||||
|
if (connection->prev)
|
||||||
|
connection->prev->next = connection->next;
|
||||||
|
else
|
||||||
|
listener->accepted_list = connection->next;
|
||||||
|
|
||||||
|
// Push it into the free connection list
|
||||||
|
connection->prev = NULL;
|
||||||
|
connection->next = state->free_connection_list;
|
||||||
|
state->free_connection_list = connection;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -646,25 +668,15 @@ void tcp_connection_destroy(tcp_connection_t *connection)
|
|||||||
assert(connection_was_accepted(connection));
|
assert(connection_was_accepted(connection));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Make sure the connection was first finished
|
// You can only call destroy on connections
|
||||||
// by being moved from the idle list to the
|
// that were at least established
|
||||||
// waiting-for-fin list.
|
assert(connection->state == TCP_STATE_ESTAB);
|
||||||
tcp_connection_finish(connection);
|
|
||||||
|
|
||||||
tcp_listener_t *listener = connection->listener;
|
// Send the FIN message
|
||||||
|
//emit_segment(connection, TCP_FLAG_FIN, 0);
|
||||||
|
//connection->state = TCP_STATE_FIN_WAIT_1;
|
||||||
|
|
||||||
// Pop connection from the waiting-for-fin list
|
// TODO: Should start a timeout here prolly
|
||||||
if (connection->prev)
|
|
||||||
connection->prev->next = connection->next;
|
|
||||||
else
|
|
||||||
listener->accepted_list = connection->next;
|
|
||||||
|
|
||||||
// Push it into the free connection list
|
|
||||||
tcp_state_t *state = listener->state;
|
|
||||||
|
|
||||||
connection->prev = NULL;
|
|
||||||
connection->next = state->free_connection_list;
|
|
||||||
state->free_connection_list = connection;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t tcp_connection_recv(tcp_connection_t *connection,
|
size_t tcp_connection_recv(tcp_connection_t *connection,
|
||||||
@@ -702,45 +714,6 @@ append_to_output_buffer(tcp_connection_t *connection,
|
|||||||
size_t tcp_connection_send(tcp_connection_t *connection, const void *src, size_t len)
|
size_t tcp_connection_send(tcp_connection_t *connection, const void *src, size_t len)
|
||||||
{
|
{
|
||||||
size_t num = append_to_output_buffer(connection, src, len);
|
size_t num = append_to_output_buffer(connection, src, len);
|
||||||
emit_segment(connection, false, false, SIZE_MAX);
|
emit_segment(connection, TCP_FLAG_ACK, SIZE_MAX);
|
||||||
return num;
|
return num;
|
||||||
}
|
|
||||||
|
|
||||||
void tcp_connection_finish(tcp_connection_t *connection)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
if (!connection->read_only) {
|
|
||||||
|
|
||||||
// Move connection from idle list to
|
|
||||||
// waiting-for-fin list
|
|
||||||
|
|
||||||
tcp_listener_t *listener = connection->listener;
|
|
||||||
|
|
||||||
// Pop it from the idle list
|
|
||||||
{
|
|
||||||
if (connection->prev)
|
|
||||||
connection->prev->next = connection->next;
|
|
||||||
else
|
|
||||||
listener->connections = connection->next;
|
|
||||||
|
|
||||||
if (connection->next)
|
|
||||||
connection->next->prev = connection->prev;
|
|
||||||
|
|
||||||
connection->prev = NULL;
|
|
||||||
connection->next = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#warning "The FIN segment should be sent here"
|
|
||||||
|
|
||||||
// Push it to the waiting-for-fin list
|
|
||||||
{
|
|
||||||
connection->prev = NULL;
|
|
||||||
connection->next = listener->connections_waiting_for_fin;
|
|
||||||
listener->connections_waiting_for_fin = connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now mark the connection as read-only
|
|
||||||
connection->read_only = true;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
@@ -76,6 +76,27 @@ struct tcp_connection_t {
|
|||||||
ip_address_t peer_ip; // Network byte order
|
ip_address_t peer_ip; // Network byte order
|
||||||
uint16_t peer_port; // CPU byte order
|
uint16_t peer_port; // CPU byte order
|
||||||
|
|
||||||
|
// Send Sequence Space
|
||||||
|
//
|
||||||
|
// 1 2 3 4
|
||||||
|
// ----------|----------|----------|----------
|
||||||
|
// SND.UNA SND.NXT SND.UNA
|
||||||
|
// +SND.WND
|
||||||
|
//
|
||||||
|
// 1 - old sequence numbers which have been acknowledged
|
||||||
|
// 2 - sequence numbers of unacknowledged data
|
||||||
|
// 3 - sequence numbers allowed for new data transmission
|
||||||
|
// 4 - future sequence numbers which are not yet allowed
|
||||||
|
//
|
||||||
|
// Receive Sequence Space
|
||||||
|
//
|
||||||
|
// 1 2 3
|
||||||
|
// ----------|----------|----------
|
||||||
|
// RCV.NXT RCV.NXT
|
||||||
|
// +RCV.WND
|
||||||
|
//
|
||||||
|
// (From RFC 793 section 3.2, // https://www.ietf.org/rfc/rfc793.txt)
|
||||||
|
|
||||||
uint32_t rcv_unread; // It's the sequence number of the first
|
uint32_t rcv_unread; // It's the sequence number of the first
|
||||||
// byte stored in the input buffer, such
|
// byte stored in the input buffer, such
|
||||||
// that [rcv_next - rcv_unread] is the
|
// that [rcv_next - rcv_unread] is the
|
||||||
|
|||||||
Reference in New Issue
Block a user