net: minor improvements in tcp client sockets
[quarnos.git] / resources / net / tcp_client_socket.cpp
blob6a0810581edaf1015a8c9026e90b5fcbfd90ef99
1 #include "tcp_client_socket.h"
3 using namespace net;
5 void poll(volatile int *value, int wait_for) {
6 while (*value != wait_for) asm volatile("nop");
9 void tcp_client_socket::connect(const ipv4_addr &addr, int port) {
10 clean();
12 server = addr;
13 server_port = port;
14 client_port = down->acquire_port();
16 down_tcp->listen(client_port, tcp::port_listener::method(this, &tcp_client_socket::receive));
18 sequence_number = 1;
20 /* TCP three-way handshake
21 * Part I: SYN packet */
22 state = syn_sent;
23 down_tcp->send(addr, port, client_port, buffer::empty, tcp::tcp_syn, sequence_number++, 0);
24 poll(reinterpret_cast<volatile int*>(&state), established);
27 void tcp_client_socket::receive(const ipv4_addr &addr, u16 sender_port, const buffer &data, tcp::tcp_flags flags, int seq, int ack) {
28 if (addr != server || server_port != server_port)
29 return;
31 ack_number = seq;
33 if (state == syn_sent) {
34 /* In the second part of handshake we should receive SYN/ACK packet */
35 if (flags != (tcp::tcp_syn | tcp::tcp_ack)/* || ack != sequence_number - 1*/)
36 return;
38 /* TCP three-way handshake
39 * Part III: ACK packet */
40 state = established;
41 down_tcp->send(addr, sender_port, client_port, buffer::empty, tcp::tcp_ack, sequence_number++, seq + 1);
42 return;
43 } else if ((state == fin_wait1 || state == fin_wait2) && flags == (tcp::tcp_fin | tcp::tcp_ack)) {
44 state = closed;
45 } else if (state == fin_wait1 && flags == tcp::tcp_ack) {
46 state = fin_wait2;
47 } else if (state == established && flags == tcp::tcp_fin) {
48 state = last_ack;
49 down_tcp->send(server, server_port, client_port, buffer::empty, (tcp::tcp_flags)(tcp::tcp_fin | tcp::tcp_ack), sequence_number++, ack + 1);
50 } else if (state == last_ack && flags == tcp::tcp_ack) {
51 state = closed;
54 if (state == established) {
55 incoming_data.push(data.copy());
59 tcp_client_socket::tcp_client_socket(p<transport_layer> tl) : client_socket(tl), down_tcp(tl.cast<tcp>()) { }
60 tcp_client_socket::~tcp_client_socket() {
61 clean();
64 void tcp_client_socket::write(const buffer &data) {
65 if (state == established) {
66 down.cast<tcp>()->send(server, server_port, client_port, data, (tcp::tcp_flags)(tcp::tcp_psh | tcp::tcp_ack), sequence_number, ack_number + 1);
67 sequence_number += data.get_size() > 0 ? data.get_size() : 1;
71 void tcp_client_socket::read(buffer &data) {
72 if (state == closed || state == unknown)
73 return;
75 buffer buf = incoming_data.pop();
76 data.copy_data(buf);
79 void tcp_client_socket::close() {
80 state = fin_wait1;
81 down_tcp->send(server, server_port, client_port, buffer::empty, tcp::tcp_fin, sequence_number++, 0);
82 poll(reinterpret_cast<volatile int*>(&state), closed);
85 void tcp_client_socket::clean() {
86 if (state == unknown)
87 return;
89 if (state != closed)
90 close();
92 if (client_port) {
93 // down.cast<tcp>()->remove_listener(client_port, tcp::port_listener::method(this, &tcp_client_socket::receive));
94 down->release_port(client_port);
95 client_port = 0;
98 state = unknown;