From 6bfaab8ab3f48a0b8c9ea8ebb6d3a5fe715e26f3 Mon Sep 17 00:00:00 2001 From: Andrew Galante Date: Fri, 11 Aug 2006 00:26:36 +0000 Subject: [PATCH] Beginning of TCP implementation git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18478 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../network/protocols/tcp/TCPConnection.h | 203 ++++++++++++++++++ .../kernel/network/protocols/tcp/tcp.cpp | 169 +++++++++++---- 2 files changed, 333 insertions(+), 39 deletions(-) create mode 100644 src/add-ons/kernel/network/protocols/tcp/TCPConnection.h diff --git a/src/add-ons/kernel/network/protocols/tcp/TCPConnection.h b/src/add-ons/kernel/network/protocols/tcp/TCPConnection.h new file mode 100644 index 0000000000..6d5ae586b8 --- /dev/null +++ b/src/add-ons/kernel/network/protocols/tcp/TCPConnection.h @@ -0,0 +1,203 @@ +/* + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Andrew Galante, haiku.galante@gmail.com + */ + + +typedef struct { + in_addr_t source; + in_addr_t destination; + uint16 source_port; + uint16 destination_port; +} tcp_connection_key; + + +class TCPConnection : public net_protocol { +public: + TCPConnection(net_socket *socket); + ~TCPConnection(); + + status_t Open(); + status_t Close(); + status_t Free(); + status_t Connect(const struct sockaddr *address); + status_t Accept(struct net_socket **_acceptedSocket); + status_t Bind(struct sockaddr *address); + status_t Unbind(struct sockaddr *address); + status_t Listen(int count); + status_t Shutdown(int direction); + status_t SendData(net_buffer *buffer); + status_t SendRoutedData(net_route *route, net_buffer *buffer); + status_t SendAvailable(); + status_t ReadData(size_t numBytes, uint32 flags, net_buffer **_buffer); + status_t ReadAvailable(); + + static int Compare(void *_packet, const void *_key); + static uint32 Hash(void *_packet, const void *_key, uint32 range); + static int32 HashOffset() { return offsetof(TCPConnection, fHashLink); } +private: + TCPConnection *fHashLink; + tcp_state fState; + benaphore fLock; +public: + tcp_connection_key fKey; +}; + + +TCPConnection::TCPConnection(net_socket *socket) + : + fState(CLOSED) +{ + benaphore_init(&fLock, "TCPConnection"); +} + + +TCPConnection::~TCPConnection() +{ + benaphore_destroy(&fLock); +} + + +status_t +TCPConnection::Open() +{ + return B_OK; +} + + +status_t +TCPConnection::Close() +{ + return B_OK; +} + + +status_t +TCPConnection::Free() +{ + return B_OK; +} + + +status_t +TCPConnection::Connect(const struct sockaddr *address) +{ + return B_OK; +} + + +status_t +TCPConnection::Accept(struct net_socket **_acceptedSocket) +{ + return B_OK; +} + + +status_t +TCPConnection::Bind(sockaddr *address) +{ + if (address->sa_family != AF_INET) + return EAFNOSUPPORT; + + BenaphoreLocker lock(&fLock); + + // let IP check whether there is an interface that supports the given address: + status_t status = next->module->bind(next, address); + if (status < B_OK) + return status; + + //TODO: clean this up +/* fKey.source = ((struct sockaddr_in *)address)->sin_addr; + fKey.source_port = sAddressModule->get_port(address); + fKey.destination = INADDR_ANY; + fKey.destination_port = 0;*/ + + return B_OK; +} + + +status_t +TCPConnection::Unbind(struct sockaddr *address) +{ + return B_OK; +} + + +status_t +TCPConnection::Listen(int count) +{ + return B_OK; +} + + +status_t +TCPConnection::Shutdown(int direction) +{ + return B_OK; +} + + +status_t +TCPConnection::SendData(net_buffer *buffer) +{ + return B_ERROR; +} + + +status_t +TCPConnection::SendRoutedData(net_route *route, net_buffer *buffer) +{ + return B_ERROR; +} + + +status_t +TCPConnection::SendAvailable() +{ + return B_ERROR; +} + + +status_t +TCPConnection::ReadData(size_t numBytes, uint32 flags, net_buffer **_buffer) +{ + return B_ERROR; +} + + +status_t +TCPConnection::ReadAvailable() +{ + return B_ERROR; +} + + +int +TCPConnection::Compare(void *_packet, const void *_key) +{ + const tcp_connection_key *key = (tcp_connection_key *)_key; + tcp_connection_key *packetKey = &((TCPConnection *)_packet)->fKey; + + if (key->source == packetKey->source + && key->destination == packetKey->destination + && key->source_port == packetKey->source_port + && key->destination_port == packetKey->destination_port) + return 0; + + return 1; +} + + +uint32 +TCPConnection::Hash(void *_packet, const void *_key, uint32 range) +{ + const tcp_connection_key *key = (tcp_connection_key *)_key; + if (_packet != NULL) + key = &((TCPConnection *)_packet)->fKey; + + return ((uint32)key->source_port << 16 ^ (uint32)key->destination_port + ^ key->source ^ key->destination) % range; +} diff --git a/src/add-ons/kernel/network/protocols/tcp/tcp.cpp b/src/add-ons/kernel/network/protocols/tcp/tcp.cpp index 6b260e8b3e..bcf1f81170 100644 --- a/src/add-ons/kernel/network/protocols/tcp/tcp.cpp +++ b/src/add-ons/kernel/network/protocols/tcp/tcp.cpp @@ -7,6 +7,8 @@ */ +#include +#include #include #include @@ -14,22 +16,51 @@ #include #include +#include #include #include +#include + +#include +#include +#include + +#include +#include + +#define TRACE_TCP +#ifdef TRACE_TCP +# define TRACE(x) dprintf x +# define TRACE_BLOCK(x) dump_block x +#else +# define TRACE(x) +# define TRACE_BLOCK(x) +#endif + + +#define MAX_HASH_TCP 64 + +static net_domain *sDomain; +static net_address_module_info *sAddressModule; +//static net_buffer_module_info *sBufferModule; +static net_datalink_module_info *sDatalinkModule; +static net_stack_module_info *sStackModule; +static hash_table *sTCPHash; +static benaphore sTCPLock; #include "tcp.h" - -struct tcp_protocol : net_protocol { -}; +#include "TCPConnection.h" net_protocol * tcp_init_protocol(net_socket *socket) { - tcp_protocol *protocol = new (std::nothrow) tcp_protocol; + socket->protocol = IPPROTO_TCP; + TCPConnection *protocol = new (std::nothrow) TCPConnection(socket); if (protocol == NULL) return NULL; + TRACE(("Created new TCPConnection %p\n", protocol)); return protocol; } @@ -37,7 +68,7 @@ tcp_init_protocol(net_socket *socket) status_t tcp_uninit_protocol(net_protocol *protocol) { - delete protocol; + delete (TCPConnection *)protocol; return B_OK; } @@ -45,35 +76,35 @@ tcp_uninit_protocol(net_protocol *protocol) status_t tcp_open(net_protocol *protocol) { - return B_OK; + return ((TCPConnection *)protocol)->Open(); } status_t tcp_close(net_protocol *protocol) { - return B_OK; + return ((TCPConnection *)protocol)->Close(); } status_t tcp_free(net_protocol *protocol) { - return B_OK; + return ((TCPConnection *)protocol)->Free(); } status_t tcp_connect(net_protocol *protocol, const struct sockaddr *address) { - return B_ERROR; + return ((TCPConnection *)protocol)->Connect(address); } status_t tcp_accept(net_protocol *protocol, struct net_socket **_acceptedSocket) { - return B_ERROR; + return ((TCPConnection *)protocol)->Accept(_acceptedSocket); } @@ -89,28 +120,31 @@ tcp_control(net_protocol *protocol, int level, int option, void *value, status_t tcp_bind(net_protocol *protocol, struct sockaddr *address) { - return B_ERROR; + TRACE(("tcp_bind(%p) on address %s\n", protocol, + AddressString(sDomain, address, true).Data())); + TCPConnection *connection = (TCPConnection *)protocol; + return connection->Bind(address); } status_t tcp_unbind(net_protocol *protocol, struct sockaddr *address) { - return B_ERROR; + return ((TCPConnection *)protocol)->Unbind(address); } status_t tcp_listen(net_protocol *protocol, int count) { - return B_ERROR; + return ((TCPConnection *)protocol)->Listen(count); } status_t tcp_shutdown(net_protocol *protocol, int direction) { - return B_ERROR; + return ((TCPConnection *)protocol)->Shutdown(direction); } @@ -132,7 +166,7 @@ tcp_send_routed_data(net_protocol *protocol, struct net_route *route, ssize_t tcp_send_avail(net_protocol *protocol) { - return B_ERROR; + return ((TCPConnection *)protocol)->SendAvailable(); } @@ -140,14 +174,14 @@ status_t tcp_read_data(net_protocol *protocol, size_t numBytes, uint32 flags, net_buffer **_buffer) { - return B_ERROR; + return ((TCPConnection *)protocol)->ReadData(numBytes, flags, _buffer); } ssize_t tcp_read_avail(net_protocol *protocol) { - return B_ERROR; + return ((TCPConnection *)protocol)->ReadAvailable(); } @@ -189,36 +223,93 @@ tcp_error_reply(net_protocol *protocol, net_buffer *causedError, uint32 code, // #pragma mark - +static status_t +tcp_init() +{ + status_t status; + + sDomain = sStackModule->get_domain(AF_INET); + sAddressModule = sDomain->address_module; + + status = get_module(NET_STACK_MODULE_NAME, (module_info **)&sStackModule); + if (status < B_OK) + return status; + +/* status = get_module(NET_BUFFER_MODULE_NAME, (module_info **)&sBufferModule); + if (status < B_OK) + goto err1;*/ + + status = get_module(NET_DATALINK_MODULE_NAME, (module_info **)&sDatalinkModule); + if (status < B_OK) + goto err2; + + sTCPHash = hash_init(MAX_HASH_TCP, TCPConnection::HashOffset(), + &TCPConnection::Compare, &TCPConnection::Hash); + if (sTCPHash == NULL) + goto err3; + + status = benaphore_init(&sTCPLock, "TCP Hash Lock"); + if (status < B_OK) + goto err4; + + status = sStackModule->register_domain_protocols(AF_INET, SOCK_STREAM, IPPROTO_IP, + "network/protocols/tcp/v1", + "network/protocols/ipv4/v1", + NULL); + if (status < B_OK) + goto err5; + + status = sStackModule->register_domain_protocols(AF_INET, SOCK_STREAM, IPPROTO_TCP, + "network/protocols/tcp/v1", + "network/protocols/ipv4/v1", + NULL); + if (status < B_OK) + goto err5; + + status = sStackModule->register_domain_receiving_protocol(AF_INET, IPPROTO_TCP, + "network/protocols/tcp/v1"); + if (status < B_OK) + goto err5; + + return B_OK; + +err5: + benaphore_destroy(&sTCPLock); +err4: + hash_uninit(sTCPHash); +err3: + put_module(NET_DATALINK_MODULE_NAME); +err2: +/* put_module(NET_BUFFER_MODULE_NAME); +err1:*/ + put_module(NET_STACK_MODULE_NAME); + + TRACE(("init_tcp() fails with %lx (%s)\n", status, strerror(status))); + return status; + +} + +static status_t +tcp_uninit() +{ + benaphore_destroy(&sTCPLock); + hash_uninit(sTCPHash); + put_module(NET_DATALINK_MODULE_NAME); + put_module(NET_BUFFER_MODULE_NAME); + put_module(NET_STACK_MODULE_NAME); + + return B_OK; +} static status_t tcp_std_ops(int32 op, ...) { switch (op) { case B_MODULE_INIT: - { - net_stack_module_info *stack; - status_t status = get_module(NET_STACK_MODULE_NAME, (module_info **)&stack); - if (status < B_OK) - return status; - - stack->register_domain_protocols(AF_INET, SOCK_STREAM, IPPROTO_IP, - "network/protocols/tcp/v1", - "network/protocols/ipv4/v1", - NULL); - stack->register_domain_protocols(AF_INET, SOCK_STREAM, IPPROTO_TCP, - "network/protocols/tcp/v1", - "network/protocols/ipv4/v1", - NULL); - - stack->register_domain_receiving_protocol(AF_INET, IPPROTO_TCP, - "network/protocols/tcp/v1"); - - put_module(NET_STACK_MODULE_NAME); - return B_OK; - } + return tcp_init(); case B_MODULE_UNINIT: - return B_OK; + return tcp_uninit(); default: return B_ERROR;