From 31731332fe45dcbd952c2075492046c079c5f35d Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 16 Jul 2009 01:35:19 +0200 Subject: [PATCH] net: tcp_client_socket connection state routines --- resources/net/tcp_client_socket.cpp | 56 ++++++++++++++++++++++++++++++++----- resources/net/tcp_client_socket.h | 18 ++++++++++-- 2 files changed, 65 insertions(+), 9 deletions(-) diff --git a/resources/net/tcp_client_socket.cpp b/resources/net/tcp_client_socket.cpp index 26c2299..c2a7921 100644 --- a/resources/net/tcp_client_socket.cpp +++ b/resources/net/tcp_client_socket.cpp @@ -2,7 +2,13 @@ using namespace net; +void poll(volatile int *value, int wait_for) { + while (*value != wait_for) asm volatile("nop"); +} + void tcp_client_socket::connect(const ipv4_addr &addr, int port) { + clean(); + server = addr; server_port = port; client_port = down->acquire_port(); @@ -10,46 +16,82 @@ void tcp_client_socket::connect(const ipv4_addr &addr, int port) { // down.cast()->listen(client_port, tcp::port_listener::method(this, &tcp_client_socket::receive)); sequence_number = 1; - negotiation = true; /* TCP three-way handshake * Part I: SYN packet */ + state = syn_sent; down.cast()->send(addr, port, client_port, buffer::empty, tcp::tcp_syn, sequence_number++, 0); - + poll(reinterpret_cast(&state), established); } void tcp_client_socket::receive(const ipv4_addr &addr, u16 sender_port, const buffer &data, tcp::tcp_flags flags, int seq, int ack) { if (addr != server || server_port != server_port) return; - if (negotiation) { + ack_number = seq; + + if (state == syn_sent) { /* In the second part of handshake we should receive SYN/ACK packet */ if (flags != (tcp::tcp_syn | tcp::tcp_ack) || ack != sequence_number - 1) return; - negotiation = false; /* TCP three-way handshake * Part III: ACK packet */ + state = established; down.cast()->send(addr, sender_port, client_port, buffer::empty, tcp::tcp_ack, sequence_number++, seq); return; + } else if ((state == fin_wait1 || state == fin_wait2) && flags == (tcp::tcp_fin | tcp::tcp_ack)) { + state = closed; + } else if (state == fin_wait1 && flags == tcp::tcp_ack) { + state = fin_wait2; + } else if (state == established && flags == tcp::tcp_fin) { + state = last_ack; + down.cast()->send(server, server_port, client_port, buffer::empty, (tcp::tcp_flags)(tcp::tcp_fin | tcp::tcp_ack), sequence_number++, ack); + } else if (state == last_ack && flags == tcp::tcp_ack) { + state = closed; + } + + if (state == established) { + incoming_data.push(data.copy()); } } tcp_client_socket::tcp_client_socket(p tl) : client_socket(tl) { } tcp_client_socket::~tcp_client_socket() { - close(); + clean(); } void tcp_client_socket::write(const buffer &data) { - down.cast()->send(server, server_port, client_port, data, tcp::tcp_none, sequence_number++, ack_number); + if (state == established) + down.cast()->send(server, server_port, client_port, data, tcp::tcp_none, sequence_number++, ack_number); } -void tcp_client_socket::read(buffer &data) { } +void tcp_client_socket::read(buffer &data) { + if (state == closed || state == unknown) + return; + + buffer buf = incoming_data.pop(); + data.copy_data(buf); +} void tcp_client_socket::close() { + state = fin_wait1; + down.cast()->send(server, server_port, client_port, buffer::empty, tcp::tcp_fin, sequence_number++, 0); + poll(reinterpret_cast(&state), closed); +} + +void tcp_client_socket::clean() { + if (state == unknown) + return; + + if (state != closed) + close(); + if (client_port) { // down.cast()->remove_listener(client_port, tcp::port_listener::method(this, &tcp_client_socket::receive)); down->release_port(client_port); client_port = 0; } + + state = unknown; } diff --git a/resources/net/tcp_client_socket.h b/resources/net/tcp_client_socket.h index 874533a..889ad54 100644 --- a/resources/net/tcp_client_socket.h +++ b/resources/net/tcp_client_socket.h @@ -18,10 +18,24 @@ namespace net { int sequence_number; int ack_number; - bool negotiation; + enum connection_state { + unknown, + //listen, + syn_sent, + //syn_recv, + established, + fin_wait1, + fin_wait2, + //time_wait, + //close_wait, + last_ack, + closed + }; + + volatile connection_state state; void receive(const ipv4_addr &addr, u16 sender_port, const buffer &data, tcp::tcp_flags, int, int); - + void clean(); public: tcp_client_socket(p tl); ~tcp_client_socket(); -- 2.11.4.GIT