From f929028570c4be1e49e817894dc505e8662a4c69 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 14 Jul 2009 23:03:53 +0200 Subject: [PATCH] net: partial implementation of tcp --- libs/buffer.h | 5 +++ libs/string.cpp | 3 ++ manes/start.cpp | 11 +++++- resources/Makefile | 2 +- resources/net/arp.h | 2 - resources/net/ipv4.cpp | 1 - resources/net/tcp.cpp | 71 ++++++++++++++++++++++++++++++++++++ resources/net/tcp.h | 73 +++++++++++++++++++++++++++++++++++++ resources/net/tcp_client_socket.cpp | 55 ++++++++++++++++++++++++++++ resources/net/tcp_client_socket.h | 38 +++++++++++++++++++ resources/net/udp.cpp | 1 + resources/rtl8139.cpp | 9 +++-- 12 files changed, 262 insertions(+), 9 deletions(-) create mode 100644 resources/net/tcp.cpp create mode 100644 resources/net/tcp.h create mode 100644 resources/net/tcp_client_socket.cpp create mode 100644 resources/net/tcp_client_socket.h diff --git a/libs/buffer.h b/libs/buffer.h index 7b6dc7b..fb74eab 100644 --- a/libs/buffer.h +++ b/libs/buffer.h @@ -64,6 +64,9 @@ public: } buffer &operator+=(const buffer &x) { + if (!math::min(x.size, size)) + return *this; + char *buf = new char[x.size + size]; memcpy(buf, address, size); memcpy((void*)((unsigned int)buf + size), x.address, x.size); @@ -115,6 +118,8 @@ public: static buffer to_mem(T &addr) { return buffer((void*)&addr, sizeof(T)); } + + static const buffer empty; }; #endif diff --git a/libs/string.cpp b/libs/string.cpp index d7dc790..6cd1379 100644 --- a/libs/string.cpp +++ b/libs/string.cpp @@ -21,6 +21,9 @@ */ #include "string.h" +#include "buffer.h" + +const buffer buffer::empty = buffer((void*)0, 0); #define assert(x,y) diff --git a/manes/start.cpp b/manes/start.cpp index 0679468..7494f3d 100644 --- a/manes/start.cpp +++ b/manes/start.cpp @@ -70,6 +70,7 @@ #include "resources/net/arp.h" #include "resources/net/udp.h" #include "resources/net/icmp.h" +#include "resources/net/tcp.h" using namespace services; using namespace modules; @@ -177,17 +178,25 @@ extern "C" void _start() { string str = "zuooooooooooooooooooooooooooooooooooooooooooa"; + tcp t; + t.set_internet_layer(&ip); + p tcli = t.create_client(); + tcli->connect(ipv4_addr::from_le(192 << 24 | 168 << 16 | 1 << 8 | 3), 80); + tcli->write(str.to_mem()); + tcli->close(); + udp u; u.set_internet_layer(&ip); p cli = u.create_client(); cli->connect(ipv4_addr::from_le(192 << 24 | 168 << 16 | 1 << 8 | 2), 53); cli->write(str.to_mem()); + cli->close(); icmp ping; ping.set_internet_layer(&ip); ping.ping(ipv4_addr::from_le(192 << 24 | 168 << 16 | 1 << 8 | 2)); - // ping.ping(ipv4_addr::from_le(192 << 24 | 168 << 16 | 1 << 8 | 2)); + ping.ping(ipv4_addr::from_le(192 << 24 | 168 << 16 | 1 << 8 | 2)); while (true) asm("hlt"); } diff --git a/resources/Makefile b/resources/Makefile index b23adb3..45f2807 100644 --- a/resources/Makefile +++ b/resources/Makefile @@ -19,7 +19,7 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # -RESOURCE = isa.o pci.o device.o keybscr.o x86_keybscr.o fdc.o speaker.o prvl.o foma.o fat.o fs.o file.o virtual_bus.o pio.o physmem.o unknown.o ne2k.o usb.o uhci.o bus.o net/arp.o net/mac_addr.o net/arp_table.o net/ethernet.o net/link_layer.o net/ipv4.o net/icmp.o net/ipv4_addr.o net/udp.o net/udp_server_socket.o net/udp_client_socket.o rtl8139.o slob.o # rs232.o +RESOURCE = isa.o pci.o device.o keybscr.o x86_keybscr.o fdc.o speaker.o prvl.o foma.o fat.o fs.o file.o virtual_bus.o pio.o physmem.o unknown.o ne2k.o usb.o uhci.o bus.o net/arp.o net/mac_addr.o net/arp_table.o net/ethernet.o net/link_layer.o net/ipv4.o net/icmp.o net/ipv4_addr.o net/udp.o net/udp_server_socket.o net/udp_client_socket.o net/tcp.o net/tcp_client_socket.o rtl8139.o slob.o # rs232.o OBJS = $(MANES) $(RESOURCE) diff --git a/resources/net/arp.h b/resources/net/arp.h index 1d05804..bcf8698 100644 --- a/resources/net/arp.h +++ b/resources/net/arp.h @@ -65,8 +65,6 @@ namespace net { mac_addr get_haddr(const ipv4_addr &ipaddr); void receive_packet(p pkg); - - //static void register_type(); }; } diff --git a/resources/net/ipv4.cpp b/resources/net/ipv4.cpp index e718f89..0de57de 100644 --- a/resources/net/ipv4.cpp +++ b/resources/net/ipv4.cpp @@ -29,7 +29,6 @@ void ipv4::send_data(const ipv4_addr &addr, int prot, const buffer &x) { array words = array::from_buffer(buffer::to_mem(pkg)); u32 sum = 0; - for (unsigned int i = 0; i < sizeof(ipv4_packet)/2; i++) sum += words[i]; diff --git a/resources/net/tcp.cpp b/resources/net/tcp.cpp new file mode 100644 index 0000000..e1d8370 --- /dev/null +++ b/resources/net/tcp.cpp @@ -0,0 +1,71 @@ +/* Based on RFC793 */ + +#include "tcp.h" +#include "ipv4.h" + +#include "arch/low/general.h" + +#include "libs/pointer.h" +#include "libs/array.h" + +#include "tcp_client_socket.h" + +using namespace net; + +void tcp::send(const ipv4_addr &addr, u16 dst_port, u16 src_port, const buffer &data, tcp_flags flags, int seq, int ack) { + p pkg = new tcp_packet; + pkg->sender_port = to_be16(src_port); + pkg->receiver_port = to_be16(dst_port); + pkg->seq = to_be32(seq); + pkg->ack = to_be32(ack); + pkg->header_size = sizeof(tcp_packet) << 2; + pkg->flags = flags; + pkg->window_size = to_be16(1000); /*wtf?*/ + pkg->checksum = 0; + pkg->piority = 0; + + + p ph = new pseudo_header; + ph->source = down.cast()->get_my_ip().to_be(); + ph->destination = addr.to_be(); + ph->zero = 0; + ph->protocol = 6; + ph->length = to_be16(sizeof(tcp_packet) + data.get_size()); + array ph_words = array::from_buffer(buffer::to_mem(ph)); + + buffer buf = buffer::to_mem(pkg); + + buf += data; + + array words = array::from_buffer(buf); + u32 sum = 0; + + for (unsigned int i = 0; i < (sizeof(tcp_packet) + data.get_size()) / 2; i++) + sum += words[i]; + + if (data.get_size() % 2) + sum += (u16)data[data.get_size() - 1]; + + for (unsigned int i = 0; i < sizeof(pseudo_header) / 2; i++) + sum += ph_words[i]; + +// ph.dispose(); + + sum = (sum & 0xffff) + (sum >> 16); + sum += (sum >> 16); + + buf.cast()->checksum = to_le16(~sum); + + down->send_data(addr, 6, buf); + +// pkg.dispose(); +} + +void tcp::receive(const ipv4_addr &, const buffer &data) { +} + +p tcp::create_client() { + return (client_socket*)new tcp_client_socket(this); +} + +p tcp::create_server(int port) { } diff --git a/resources/net/tcp.h b/resources/net/tcp.h new file mode 100644 index 0000000..d97453d --- /dev/null +++ b/resources/net/tcp.h @@ -0,0 +1,73 @@ +#ifndef _TCP_H_ +#define _TCP_H_ + +#include "transport_layer.h" +#include "ipv4_addr.h" + +namespace net { + class tcp : public transport_layer { + private: + struct pseudo_header { + u32 source; + u32 destination; + u8 zero; + u8 protocol; + u16 length; + } __attribute__((packed)); + + struct tcp_packet { + u16 sender_port; + u16 receiver_port; + u32 seq; + u32 ack; + u8 header_size; + u8 flags; + u16 window_size; + u16 checksum; + u16 piority; + } __attribute__((packed)); + + list ports; + list > listeners; + + int last_port; + + void receive(const ipv4_addr &, const buffer&); + + public: + enum tcp_flags { + tcp_none = 0, + tcp_fin = 1, + tcp_syn = 2, + tcp_rst = 4, + tcp_psh = 8, + tcp_ack = 0x10, + tcp_urg = 0x20, + tcp_ecn = 0x40, + tcp_cwr = 0x80 + }; + + tcp() : last_port(49152) { } + + typedef delegate port_listener; + void set_internet_layer(p x) { + down = x; + down->listen(6, delegate::method(this, &tcp::receive)); + } + + void send(const ipv4_addr&, u16, u16, const buffer &, tcp_flags, int, int); + void listen(u16, port_listener); + void remove_listener(u16, port_listener); + + int acquire_port() { + return last_port++; + } + + void release_port(int) { } + + p create_client(); + p create_server(int port); + }; +} + +#endif diff --git a/resources/net/tcp_client_socket.cpp b/resources/net/tcp_client_socket.cpp new file mode 100644 index 0000000..26c2299 --- /dev/null +++ b/resources/net/tcp_client_socket.cpp @@ -0,0 +1,55 @@ +#include "tcp_client_socket.h" + +using namespace net; + +void tcp_client_socket::connect(const ipv4_addr &addr, int port) { + server = addr; + server_port = port; + client_port = down->acquire_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 */ + down.cast()->send(addr, port, client_port, buffer::empty, tcp::tcp_syn, sequence_number++, 0); + +} + +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) { + /* 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 */ + down.cast()->send(addr, sender_port, client_port, buffer::empty, tcp::tcp_ack, sequence_number++, seq); + return; + } +} + +tcp_client_socket::tcp_client_socket(p tl) : client_socket(tl) { } +tcp_client_socket::~tcp_client_socket() { + close(); +} + +void tcp_client_socket::write(const buffer &data) { + 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::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; + } +} diff --git a/resources/net/tcp_client_socket.h b/resources/net/tcp_client_socket.h new file mode 100644 index 0000000..874533a --- /dev/null +++ b/resources/net/tcp_client_socket.h @@ -0,0 +1,38 @@ +#ifndef _TCP_CLIENT_SOCKET_H_ +#define _TCP_CLIENT_SOCKET_H_ + +#include "tcp.h" +#include "client_socket.h" +#include "libs/fifo.h" + +namespace net { + class tcp_client_socket : public client_socket { + private: + int client_port; + + int server_port; + ipv4_addr server; + + fifo incoming_data; + + int sequence_number; + int ack_number; + + bool negotiation; + + void receive(const ipv4_addr &addr, u16 sender_port, const buffer &data, tcp::tcp_flags, int, int); + + public: + tcp_client_socket(p tl); + ~tcp_client_socket(); + + void connect(const ipv4_addr &addr, int port); + + void write(const buffer &data); + void read(buffer &data); + + void close(); + }; +} + +#endif diff --git a/resources/net/udp.cpp b/resources/net/udp.cpp index 5c49712..019191f 100644 --- a/resources/net/udp.cpp +++ b/resources/net/udp.cpp @@ -54,6 +54,7 @@ void udp::send(const ipv4_addr &addr, u16 dst_port, u16 src_port, const buffer & } void udp::receive(const ipv4_addr &sender, const buffer &data) { +return; p pkg = data.cast(); for (int i = 0; i < ports.get_count(); i++) diff --git a/resources/rtl8139.cpp b/resources/rtl8139.cpp index 8615209..8dba93b 100644 --- a/resources/rtl8139.cpp +++ b/resources/rtl8139.cpp @@ -145,21 +145,22 @@ void rtl8139::receive_packet() { received_index = (received_index + size + 4 + 3) & ~3; received_index %= 8192 + 16; - if (status & 1) { + // if (status & 1) { u8* buf = new u8[size]; memcpy(buf, pkg, size); pkg = (packet*)buf; id.outw(capr, received_index - 16); - } + //} id.outw(isr, 1); id.inw(isr); - if (status & 1) + // if (status & 1) receiver(buffer((void*)&pkg[1], pkg->size - 4)); + + delete []buf; } -// delete []buf; } void rtl8139::get_mac_addr(u8 *addr) const { -- 2.11.4.GIT