From 03d7f17e07da19253587845073315010febc031a Mon Sep 17 00:00:00 2001 From: Hugo Santos Date: Mon, 16 Apr 2007 00:27:39 +0000 Subject: [PATCH] made TCP handle multiple domains. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20718 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../network/protocols/tcp/EndpointManager.cpp | 98 +++++++--- .../network/protocols/tcp/EndpointManager.h | 19 +- .../network/protocols/tcp/TCPEndpoint.cpp | 63 ++++--- .../network/protocols/tcp/TCPEndpoint.h | 10 ++ .../kernel/network/protocols/tcp/tcp.cpp | 169 ++++++++---------- .../kernel/network/protocols/tcp/tcp.h | 9 +- 6 files changed, 218 insertions(+), 150 deletions(-) diff --git a/src/add-ons/kernel/network/protocols/tcp/EndpointManager.cpp b/src/add-ons/kernel/network/protocols/tcp/EndpointManager.cpp index 0517c5a73f..4e92b87eda 100644 --- a/src/add-ons/kernel/network/protocols/tcp/EndpointManager.cpp +++ b/src/add-ons/kernel/network/protocols/tcp/EndpointManager.cpp @@ -26,6 +26,7 @@ struct connection_key { + net_address_module_info *address_module; const sockaddr *local; const sockaddr *peer; }; @@ -42,7 +43,8 @@ static const uint16 kLastReservedPort = 1023; static const uint16 kFirstEphemeralPort = 40000; -EndpointManager::EndpointManager() +EndpointManager::EndpointManager(net_domain *domain) + : fDomain(domain) { fConnectionHash = hash_init(kConnectionHashBuckets, offsetof(TCPEndpoint, fConnectionHashNext), @@ -89,6 +91,7 @@ TCPEndpoint * EndpointManager::_LookupConnection(sockaddr *local, sockaddr *peer) { connection_key key; + key.address_module = AddressModule(); key.local = local; key.peer = peer; @@ -109,9 +112,6 @@ EndpointManager::_DumpConnections() { RecursiveLocker lock(&fLock); - if (gDomain == NULL) - return; - struct hash_iterator iterator; hash_open(fConnectionHash, &iterator); @@ -120,8 +120,8 @@ EndpointManager::_DumpConnections() TCPEndpoint *endpoint; while ((endpoint = (TCPEndpoint *)hash_next(fConnectionHash, &iterator)) != NULL) { TRACE((" TCPEndpoint %p: local %s, peer %s\n", endpoint, - AddressString(gDomain, (sockaddr *)&endpoint->socket->address, true).Data(), - AddressString(gDomain, (sockaddr *)&endpoint->socket->peer, true).Data())); + AddressString(Domain(), (sockaddr *)&endpoint->socket->address, true).Data(), + AddressString(Domain(), (sockaddr *)&endpoint->socket->peer, true).Data())); } hash_close(fConnectionHash, &iterator, false); @@ -138,13 +138,14 @@ EndpointManager::SetConnection(TCPEndpoint *endpoint, sockaddr localBuffer; // need to associate this connection with a real address, not INADDR_ANY - if (gAddressModule->is_empty_address(local, false)) { - gAddressModule->set_to(&localBuffer, interfaceLocal); - gAddressModule->set_port(&localBuffer, gAddressModule->get_port(local)); + if (AddressModule()->is_empty_address(local, false)) { + AddressModule()->set_to(&localBuffer, interfaceLocal); + AddressModule()->set_port(&localBuffer, AddressModule()->get_port(local)); local = &localBuffer; } connection_key key; + key.address_module = AddressModule(); key.local = local; key.peer = peer; @@ -153,8 +154,8 @@ EndpointManager::SetConnection(TCPEndpoint *endpoint, _RemoveConnection(endpoint); - gAddressModule->set_to((sockaddr *)&endpoint->socket->address, local); - gAddressModule->set_to((sockaddr *)&endpoint->socket->peer, peer); + AddressModule()->set_to((sockaddr *)&endpoint->socket->address, local); + AddressModule()->set_to((sockaddr *)&endpoint->socket->peer, peer); return hash_insert(fConnectionHash, endpoint); } @@ -172,7 +173,7 @@ EndpointManager::FindConnection(sockaddr *local, sockaddr *peer) // no explicit endpoint exists, check for wildcard endpoints sockaddr wildcard; - gAddressModule->set_to_empty_address(&wildcard); + AddressModule()->set_to_empty_address(&wildcard); endpoint = _LookupConnection(local, &wildcard); if (endpoint != NULL) { @@ -181,8 +182,8 @@ EndpointManager::FindConnection(sockaddr *local, sockaddr *peer) } sockaddr localWildcard; - gAddressModule->set_to_empty_address(&localWildcard); - gAddressModule->set_port(&localWildcard, gAddressModule->get_port(local)); + AddressModule()->set_to_empty_address(&localWildcard); + AddressModule()->set_port(&localWildcard, AddressModule()->get_port(local)); endpoint = _LookupConnection(&localWildcard, &wildcard); if (endpoint != NULL) { @@ -217,12 +218,12 @@ EndpointManager::Bind(TCPEndpoint *endpoint) sockaddr *address = (sockaddr *)&endpoint->socket->address; TRACE(("EndpointManager::Bind(%p, %s)\n", endpoint, - AddressString(gDomain, address, true).Data())); + AddressString(Domain(), address, true).Data())); - if (gAddressModule->is_empty_address(address, true)) + if (AddressModule()->is_empty_address(address, true)) return B_BAD_VALUE; - uint16 port = gAddressModule->get_port(address); + uint16 port = AddressModule()->get_port(address); // TODO: check the root group instead? if (ntohs(port) <= kLastReservedPort && geteuid() != 0) @@ -245,7 +246,7 @@ EndpointManager::Bind(TCPEndpoint *endpoint) TCPEndpoint *last = first; while (true) { // check if this endpoint binds to a wildcard address - if (gAddressModule->is_empty_address((sockaddr *)&last->socket->address, false)) { + if (AddressModule()->is_empty_address((sockaddr *)&last->socket->address, false)) { // you cannot specialize a wildcard endpoint - you have to open the // wildcard endpoint last return B_PERMISSION_DENIED; @@ -293,9 +294,9 @@ EndpointManager::BindToEphemeral(TCPEndpoint *endpoint) TCPEndpoint *other = _LookupEndpoint(port); if (other == NULL) { // found a port - gAddressModule->set_port((sockaddr *)&endpoint->socket->address, port); + AddressModule()->set_port((sockaddr *)&endpoint->socket->address, port); TRACE((" EndpointManager::BindToEphemeral(%p) -> %s\n", endpoint, - AddressString(gDomain, (sockaddr *)&endpoint->socket->address, true).Data())); + AddressString(Domain(), (sockaddr *)&endpoint->socket->address, true).Data())); endpoint->fEndpointNextWithSamePort = NULL; hash_insert(fEndpointHash, endpoint); hash_insert(fConnectionHash, endpoint); @@ -320,7 +321,7 @@ EndpointManager::Unbind(TCPEndpoint *endpoint) RecursiveLocker locker(&fLock); if (!endpoint->fSpawned) { - TCPEndpoint *other = _LookupEndpoint(gAddressModule->get_port( + TCPEndpoint *other = _LookupEndpoint(AddressModule()->get_port( (sockaddr *)&endpoint->socket->address)); if (other != endpoint) { // remove endpoint from the list of endpoints with the same port @@ -351,6 +352,45 @@ EndpointManager::Unbind(TCPEndpoint *endpoint) } +status_t +EndpointManager::ReplyWithReset(tcp_segment_header &segment, + net_buffer *buffer) +{ + TRACE(("TCP: Sending RST...\n")); + + net_buffer *reply = gBufferModule->create(512); + if (reply == NULL) + return B_NO_MEMORY; + + AddressModule()->set_to((sockaddr *)&reply->source, + (sockaddr *)&buffer->destination); + AddressModule()->set_to((sockaddr *)&reply->destination, + (sockaddr *)&buffer->source); + + tcp_segment_header outSegment; + outSegment.flags = TCP_FLAG_RESET; + outSegment.sequence = 0; + outSegment.acknowledge = 0; + outSegment.advertised_window = 0; + outSegment.urgent_offset = 0; + + if ((segment.flags & TCP_FLAG_ACKNOWLEDGE) == 0) { + outSegment.flags |= TCP_FLAG_ACKNOWLEDGE; + outSegment.acknowledge = segment.sequence + buffer->size; + } else + outSegment.sequence = segment.acknowledge; + + status_t status = add_tcp_header(AddressModule(), outSegment, reply); + if (status == B_OK) + status = Domain()->module->send_data(NULL, reply); + + if (status != B_OK) + gBufferModule->free(reply); + + return status; +} + + // #pragma mark - hash functions @@ -360,9 +400,9 @@ EndpointManager::_ConnectionCompare(void *_endpoint, const void *_key) const connection_key *key = (connection_key *)_key; TCPEndpoint *endpoint = (TCPEndpoint *)_endpoint; - if (gAddressModule->equal_addresses_and_ports(key->local, + if (key->address_module->equal_addresses_and_ports(key->local, (sockaddr *)&endpoint->socket->address) - && gAddressModule->equal_addresses_and_ports(key->peer, + && key->address_module->equal_addresses_and_ports(key->peer, (sockaddr *)&endpoint->socket->peer)) return 0; @@ -373,20 +413,23 @@ EndpointManager::_ConnectionCompare(void *_endpoint, const void *_key) /*static*/ uint32 EndpointManager::_ConnectionHash(void *_endpoint, const void *_key, uint32 range) { + net_address_module_info *address_module; const sockaddr *local; const sockaddr *peer; if (_endpoint != NULL) { TCPEndpoint *endpoint = (TCPEndpoint *)_endpoint; + address_module = endpoint->AddressModule(); local = (sockaddr *)&endpoint->socket->address; peer = (sockaddr *)&endpoint->socket->peer; } else { const connection_key *key = (connection_key *)_key; + address_module = key->address_module; local = key->local; peer = key->peer; } - return gAddressModule->hash_address_pair(local, peer) % range; + return address_module->hash_address_pair(local, peer) % range; } @@ -396,8 +439,8 @@ EndpointManager::_EndpointCompare(void *_endpoint, const void *_key) const endpoint_key *key = (endpoint_key *)_key; TCPEndpoint *endpoint = (TCPEndpoint *)_endpoint; - return gAddressModule->get_port((sockaddr *)&endpoint->socket->address) - == key->port ? 0 : 1; + return endpoint->AddressModule()->get_port( + (sockaddr *)&endpoint->socket->address) == key->port ? 0 : 1; } @@ -406,7 +449,8 @@ EndpointManager::_EndpointHash(void *_endpoint, const void *_key, uint32 range) { if (_endpoint != NULL) { TCPEndpoint *endpoint = (TCPEndpoint *)_endpoint; - return gAddressModule->get_port((sockaddr *)&endpoint->socket->address) % range; + return endpoint->AddressModule()->get_port( + (sockaddr *)&endpoint->socket->address) % range; } const endpoint_key *key = (endpoint_key *)_key; diff --git a/src/add-ons/kernel/network/protocols/tcp/EndpointManager.h b/src/add-ons/kernel/network/protocols/tcp/EndpointManager.h index ad4f50bfc3..b4844aaf67 100644 --- a/src/add-ons/kernel/network/protocols/tcp/EndpointManager.h +++ b/src/add-ons/kernel/network/protocols/tcp/EndpointManager.h @@ -8,18 +8,24 @@ #ifndef ENDPOINT_MANAGER_H #define ENDPOINT_MANAGER_H +#include "tcp.h" + +#include #include +#include #include #include +struct net_address_module_info; +struct net_domain; class TCPEndpoint; -class EndpointManager { +class EndpointManager : public DoublyLinkedListLinkImpl { public: - EndpointManager(); + EndpointManager(net_domain *domain); ~EndpointManager(); status_t InitCheck() const; @@ -34,6 +40,13 @@ class EndpointManager { status_t BindToEphemeral(TCPEndpoint *endpoint); status_t Unbind(TCPEndpoint *endpoint); + status_t ReplyWithReset(tcp_segment_header &segment, + net_buffer *buffer); + + net_domain *Domain() const { return fDomain; } + net_address_module_info *AddressModule() const + { return Domain()->address_module; } + private: TCPEndpoint *_LookupConnection(sockaddr *local, sockaddr *peer); status_t _RemoveConnection(TCPEndpoint *endpoint); @@ -45,6 +58,8 @@ class EndpointManager { static int _EndpointCompare(void *_endpoint, const void *_key); static uint32 _EndpointHash(void *_endpoint, const void *_key, uint32 range); + net_domain *fDomain; + hash_table *fConnectionHash; hash_table *fEndpointHash; recursive_lock fLock; diff --git a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp index 3a9dd30671..e3195df452 100644 --- a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp +++ b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp @@ -158,6 +158,7 @@ WaitList::Signal() TCPEndpoint::TCPEndpoint(net_socket *socket) : + fManager(NULL), fReceiveList("tcp receive"), fSendList("tcp send"), fOptions(0), @@ -205,7 +206,10 @@ TCPEndpoint::~TCPEndpoint() gStackModule->cancel_timer(&fDelayedAcknowledgeTimer); gStackModule->cancel_timer(&fTimeWaitTimer); - gEndpointManager->Unbind(this); + if (fManager) { + fManager->Unbind(this); + return_endpoint_manager(fManager); + } recursive_lock_destroy(&fLock); } @@ -234,7 +238,14 @@ status_t TCPEndpoint::Open() { TRACE("Open()"); - // nothing to do here... + + if (Domain() == NULL || AddressModule() == NULL) + return EAFNOSUPPORT; + + fManager = create_endpoint_manager(Domain()); + if (fManager == NULL) + return EAFNOSUPPORT; + return B_OK; } @@ -304,7 +315,7 @@ status_t TCPEndpoint::Connect(const struct sockaddr *address) { TRACE("Connect() on address %s", - AddressString(gDomain, address, true).Data()); + AddressString(Domain(), address, true).Data()); RecursiveLocker locker(&fLock); @@ -319,14 +330,14 @@ TCPEndpoint::Connect(const struct sockaddr *address) // get a net_route if there isn't one // TODO: get a net_route_info instead! if (fRoute == NULL) { - fRoute = gDatalinkModule->get_route(gDomain, (sockaddr *)address); + fRoute = gDatalinkModule->get_route(Domain(), (sockaddr *)address); TRACE(" Connect(): Using Route %p", fRoute); if (fRoute == NULL) return ENETUNREACH; } // make sure connection does not already exist - status_t status = gEndpointManager->SetConnection(this, + status_t status = fManager->SetConnection(this, (sockaddr *)&socket->address, address, fRoute->interface->address); if (status < B_OK) { TRACE(" Connect(): could not add connection: %s!", strerror(status)); @@ -413,7 +424,7 @@ TCPEndpoint::Bind(sockaddr *address) return B_BAD_VALUE; TRACE("Bind() on address %s", - AddressString(gDomain, address, true).Data()); + AddressString(Domain(), address, true).Data()); RecursiveLocker lock(fLock); @@ -425,13 +436,13 @@ TCPEndpoint::Bind(sockaddr *address) if (status < B_OK) return status; - if (gAddressModule->get_port(address) == 0) - status = gEndpointManager->BindToEphemeral(this); + if (AddressModule()->get_port(address) == 0) + status = fManager->BindToEphemeral(this); else - status = gEndpointManager->Bind(this); + status = fManager->Bind(this); TRACE(" Bind() bound to %s (status %i)", - AddressString(gDomain, (sockaddr *)&socket->address, true).Data(), + AddressString(Domain(), (sockaddr *)&socket->address, true).Data(), (int)status); return status; @@ -444,7 +455,7 @@ TCPEndpoint::Unbind(struct sockaddr *address) TRACE("Unbind()"); RecursiveLocker lock(fLock); - return gEndpointManager->Unbind(this); + return fManager->Unbind(this); } @@ -646,7 +657,15 @@ TCPEndpoint::ReadAvailable() bool TCPEndpoint::IsBound() const { - return !gAddressModule->is_empty_address((sockaddr *)&socket->address, true); + return !AddressModule()->is_empty_address((sockaddr *)&socket->address, true); +} + + +void +TCPEndpoint::DeleteSocket() +{ + // the next call will delete `this'. + gSocketModule->delete_socket(socket); } @@ -723,9 +742,9 @@ TCPEndpoint::ListenReceive(tcp_segment_header &segment, net_buffer *buffer) if (gSocketModule->spawn_pending_socket(socket, &newSocket) < B_OK) return DROP; - gAddressModule->set_to((sockaddr *)&newSocket->address, + AddressModule()->set_to((sockaddr *)&newSocket->address, (sockaddr *)&buffer->destination); - gAddressModule->set_to((sockaddr *)&newSocket->peer, + AddressModule()->set_to((sockaddr *)&newSocket->peer, (sockaddr *)&buffer->source); TCPEndpoint *endpoint = (TCPEndpoint *)newSocket->first_protocol; @@ -734,12 +753,12 @@ TCPEndpoint::ListenReceive(tcp_segment_header &segment, net_buffer *buffer) // TODO: proper error handling! - endpoint->fRoute = gDatalinkModule->get_route(gDomain, + endpoint->fRoute = gDatalinkModule->get_route(Domain(), (sockaddr *)&newSocket->peer); if (endpoint->fRoute == NULL) return DROP; - if (gEndpointManager->SetConnection(endpoint, (sockaddr *)&buffer->destination, + if (fManager->SetConnection(endpoint, (sockaddr *)&buffer->destination, (sockaddr *)&buffer->source, NULL) < B_OK) return DROP; @@ -1085,8 +1104,8 @@ TCPEndpoint::_SendQueued(bool force) return status; } - gAddressModule->set_to((sockaddr *)&buffer->source, (sockaddr *)&socket->address); - gAddressModule->set_to((sockaddr *)&buffer->destination, (sockaddr *)&socket->peer); + AddressModule()->set_to((sockaddr *)&buffer->source, (sockaddr *)&socket->address); + AddressModule()->set_to((sockaddr *)&buffer->destination, (sockaddr *)&socket->peer); uint32 size = buffer->size; if (length > 0 && fSendNext + segmentLength == fSendQueue.LastSequence()) { @@ -1108,10 +1127,10 @@ TCPEndpoint::_SendQueued(bool force) TRACE("SendQueued() flags %x, buffer %p, size %lu, from address %s to %s", segment.flags, buffer, buffer->size, - AddressString(gDomain, (sockaddr *)&buffer->source, true).Data(), - AddressString(gDomain, (sockaddr *)&buffer->destination, true).Data()); + AddressString(Domain(), (sockaddr *)&buffer->source, true).Data(), + AddressString(Domain(), (sockaddr *)&buffer->destination, true).Data()); - status = add_tcp_header(segment, buffer); + status = add_tcp_header(AddressModule(), segment, buffer); if (status != B_OK) { gBufferModule->free(buffer); return status; @@ -1525,6 +1544,6 @@ TCPEndpoint::_TimeWaitTimer(struct net_timer *timer, void *data) if (recursive_lock_lock(&endpoint->Lock()) < B_OK) return; - gSocketModule->delete_socket(endpoint->socket); + endpoint->DeleteSocket(); } diff --git a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h index 83fedf94ee..7b3cfb4ecc 100644 --- a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h +++ b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h @@ -64,6 +64,8 @@ class TCPEndpoint : public net_protocol { tcp_state State() const { return fState; } bool IsBound() const; + void DeleteSocket(); + status_t DelayedAcknowledge(); status_t SendAcknowledge(); status_t UpdateTimeWait(); @@ -72,6 +74,12 @@ class TCPEndpoint : public net_protocol { net_buffer *buffer); int32 Receive(tcp_segment_header& segment, net_buffer *buffer); + net_domain *Domain() const + { return socket->first_protocol->module->get_domain( + socket->first_protocol); } + net_address_module_info *AddressModule() const + { return Domain()->address_module; } + private: friend class EndpointManager; @@ -93,6 +101,8 @@ class TCPEndpoint : public net_protocol { static void _PersistTimer(net_timer *timer, void *data); static void _DelayedAcknowledgeTimer(net_timer *timer, void *data); + EndpointManager *fManager; + TCPEndpoint *fConnectionHashNext; TCPEndpoint *fEndpointHashNext; TCPEndpoint *fEndpointNextWithSamePort; diff --git a/src/add-ons/kernel/network/protocols/tcp/tcp.cpp b/src/add-ons/kernel/network/protocols/tcp/tcp.cpp index 0943c8c8ec..6a2a406f26 100644 --- a/src/add-ons/kernel/network/protocols/tcp/tcp.cpp +++ b/src/add-ons/kernel/network/protocols/tcp/tcp.cpp @@ -42,34 +42,56 @@ typedef NetBufferField TCPChecksumField; -net_domain *gDomain; -net_address_module_info *gAddressModule; net_buffer_module_info *gBufferModule; net_datalink_module_info *gDatalinkModule; net_socket_module_info *gSocketModule; net_stack_module_info *gStackModule; -EndpointManager *gEndpointManager; -status_t -set_domain(net_interface *interface = NULL) +// TODO we need to think of a better way to do this. It would be +// nice if we registered a per EndpointManager receiving +// protocol cookie, so we don't have to go through the list +// for each segment. +typedef DoublyLinkedList EndpointManagerList; +static benaphore sEndpointManagersLock; +static EndpointManagerList sEndpointManagers; + + +static EndpointManager * +endpoint_manager_for(net_domain *domain) { - if (gDomain == NULL) { - // domain and address module are not known yet, we copy them from - // the buffer's interface (if any): - if (interface == NULL || interface->domain == NULL) - gDomain = gStackModule->get_domain(AF_INET); - else - gDomain = interface->domain; - - if (gDomain == NULL) { - // this shouldn't occur, of course, but who knows... - return B_BAD_VALUE; - } - gAddressModule = gDomain->address_module; + EndpointManagerList::Iterator iterator = sEndpointManagers.GetIterator(); + while (iterator.HasNext()) { + EndpointManager *endpointManager = iterator.Next(); + if (endpointManager->Domain() == domain) + return endpointManager; } - return B_OK; + return NULL; +} + + +EndpointManager * +create_endpoint_manager(net_domain *domain) +{ + EndpointManager *endpointManager = endpoint_manager_for(domain); + if (endpointManager) + return endpointManager; + + endpointManager = new (std::nothrow) EndpointManager(domain); + if (endpointManager) + sEndpointManagers.Add(endpointManager); + + return endpointManager; +} + + +void +return_endpoint_manager(EndpointManager *endpointManager) +{ + // TODO when the connection and endpoint count reach zero + // we should remove the endpoint manager from the endpoints + // list and delete it. } @@ -125,7 +147,8 @@ add_options(tcp_segment_header &segment, uint8 *buffer, size_t bufferSize) for \a flags, \a seq \a ack and \a advertisedWindow. */ status_t -add_tcp_header(tcp_segment_header &segment, net_buffer *buffer) +add_tcp_header(net_address_module_info *addressModule, + tcp_segment_header &segment, net_buffer *buffer) { buffer->protocol = IPPROTO_TCP; @@ -138,8 +161,8 @@ add_tcp_header(tcp_segment_header &segment, net_buffer *buffer) tcp_header &header = bufferHeader.Data(); - header.source_port = gAddressModule->get_port((sockaddr *)&buffer->source); - header.destination_port = gAddressModule->get_port((sockaddr *)&buffer->destination); + header.source_port = addressModule->get_port((sockaddr *)&buffer->source); + header.destination_port = addressModule->get_port((sockaddr *)&buffer->destination); header.sequence = htonl(segment.sequence); header.acknowledge = (segment.flags & TCP_FLAG_ACKNOWLEDGE) ? htonl(segment.acknowledge) : 0; @@ -161,7 +184,7 @@ add_tcp_header(tcp_segment_header &segment, net_buffer *buffer) TRACE(("add_tcp_header(): buffer %p, flags 0x%x, seq %lu, ack %lu, win %u\n", buffer, segment.flags, segment.sequence, segment.acknowledge, segment.advertised_window)); - *TCPChecksumField(buffer) = Checksum::PseudoHeader(gAddressModule, + *TCPChecksumField(buffer) = Checksum::PseudoHeader(addressModule, gBufferModule, buffer, IPPROTO_TCP); return B_OK; @@ -222,44 +245,6 @@ process_options(tcp_segment_header &segment, net_buffer *buffer, int32 size) } -status_t -reply_with_reset(tcp_segment_header &segment, net_buffer *buffer) -{ - TRACE(("TCP: Sending RST...\n")); - - net_buffer *reply = gBufferModule->create(512); - if (reply == NULL) - return B_NO_MEMORY; - - gAddressModule->set_to((sockaddr *)&reply->source, - (sockaddr *)&buffer->destination); - gAddressModule->set_to((sockaddr *)&reply->destination, - (sockaddr *)&buffer->source); - - tcp_segment_header outSegment; - outSegment.flags = TCP_FLAG_RESET; - outSegment.sequence = 0; - outSegment.acknowledge = 0; - outSegment.advertised_window = 0; - outSegment.urgent_offset = 0; - - if ((segment.flags & TCP_FLAG_ACKNOWLEDGE) == 0) { - outSegment.flags |= TCP_FLAG_ACKNOWLEDGE; - outSegment.acknowledge = segment.sequence + buffer->size; - } else - outSegment.sequence = segment.acknowledge; - - status_t status = add_tcp_header(outSegment, reply); - if (status == B_OK) - status = gDomain->module->send_data(NULL, reply); - - if (status != B_OK) - gBufferModule->free(reply); - - return status; -} - - const char * name_for_state(tcp_state state) { @@ -350,9 +335,6 @@ tcp_uninit_protocol(net_protocol *protocol) status_t tcp_open(net_protocol *protocol) { - if (gDomain == NULL && set_domain() != B_OK) - return B_ERROR; - return ((TCPEndpoint *)protocol)->Open(); } @@ -497,9 +479,12 @@ tcp_receive_data(net_buffer *buffer) { TRACE(("TCP: Received buffer %p\n", buffer)); - if (gDomain == NULL && set_domain(buffer->interface) != B_OK) + if (buffer->interface == NULL || buffer->interface->domain == NULL) return B_ERROR; + net_domain *domain = buffer->interface->domain; + net_address_module_info *addressModule = domain->address_module; + NetBufferHeaderReader bufferHeader(buffer); if (bufferHeader.Status() < B_OK) return bufferHeader.Status(); @@ -510,16 +495,17 @@ tcp_receive_data(net_buffer *buffer) if (headerLength < sizeof(tcp_header)) return B_BAD_DATA; - if (Checksum::PseudoHeader(gAddressModule, gBufferModule, buffer, + if (Checksum::PseudoHeader(addressModule, gBufferModule, buffer, IPPROTO_TCP) != 0) return B_BAD_DATA; - gAddressModule->set_port((struct sockaddr *)&buffer->source, header.source_port); - gAddressModule->set_port((struct sockaddr *)&buffer->destination, header.destination_port); + addressModule->set_port((sockaddr *)&buffer->source, header.source_port); + addressModule->set_port((sockaddr *)&buffer->destination, + header.destination_port); TRACE((" Looking for: peer %s, local %s\n", - AddressString(gDomain, (sockaddr *)&buffer->source, true).Data(), - AddressString(gDomain, (sockaddr *)&buffer->destination, true).Data())); + AddressString(domain, (sockaddr *)&buffer->source, true).Data(), + AddressString(domain, (sockaddr *)&buffer->destination, true).Data())); //dump_tcp_header(header); //gBufferModule->dump(buffer); @@ -538,11 +524,17 @@ tcp_receive_data(net_buffer *buffer) bufferHeader.Remove(headerLength); // we no longer need to keep the header around - RecursiveLocker locker(gEndpointManager->Locker()); + BenaphoreLocker _(sEndpointManagersLock); + + EndpointManager *endpointManager = endpoint_manager_for(domain); + if (endpointManager == NULL) + return B_ERROR; + + RecursiveLocker locker(endpointManager->Locker()); int32 segmentAction = DROP; - TCPEndpoint *endpoint = gEndpointManager->FindConnection( - (struct sockaddr *)&buffer->destination, (struct sockaddr *)&buffer->source); + TCPEndpoint *endpoint = endpointManager->FindConnection( + (sockaddr *)&buffer->destination, (sockaddr *)&buffer->source); if (endpoint != NULL) { RecursiveLocker locker(endpoint->Lock()); TRACE(("Endpoint %p in state %s\n", endpoint, name_for_state(endpoint->State()))); @@ -575,13 +567,13 @@ tcp_receive_data(net_buffer *buffer) else if (segmentAction & ACKNOWLEDGE) endpoint->DelayedAcknowledge(); else if (segmentAction & DELETE) - gSocketModule->delete_socket(endpoint->socket); + endpoint->DeleteSocket(); } else if ((segment.flags & TCP_FLAG_RESET) == 0) segmentAction = DROP | RESET; if (segmentAction & RESET) { // send reset - reply_with_reset(segment, buffer); + endpointManager->ReplyWithReset(segment, buffer); } if (segmentAction & DROP) gBufferModule->free(buffer); @@ -611,52 +603,39 @@ tcp_error_reply(net_protocol *protocol, net_buffer *causedError, uint32 code, static status_t tcp_init() { - status_t status; + status_t status = benaphore_init(&sEndpointManagersLock, + "endpoint managers lock"); - gDomain = NULL; - gAddressModule = NULL; - - gEndpointManager = new (std::nothrow) EndpointManager(); - if (gEndpointManager == NULL) - return B_NO_MEMORY; - - status = gEndpointManager->InitCheck(); if (status < B_OK) - goto err1; + return status; status = gStackModule->register_domain_protocols(AF_INET, SOCK_STREAM, 0, "network/protocols/tcp/v1", "network/protocols/ipv4/v1", NULL); if (status < B_OK) - goto err1; + return status; status = gStackModule->register_domain_protocols(AF_INET, SOCK_STREAM, IPPROTO_TCP, "network/protocols/tcp/v1", "network/protocols/ipv4/v1", NULL); if (status < B_OK) - goto err1; + return status; status = gStackModule->register_domain_receiving_protocol(AF_INET, IPPROTO_TCP, "network/protocols/tcp/v1"); if (status < B_OK) - goto err1; + return status; return B_OK; - -err1: - delete gEndpointManager; - - TRACE(("init_tcp() fails with %lx (%s)\n", status, strerror(status))); - return status; } static status_t tcp_uninit() { - delete gEndpointManager; + benaphore_destroy(&sEndpointManagersLock); return B_OK; } diff --git a/src/add-ons/kernel/network/protocols/tcp/tcp.h b/src/add-ons/kernel/network/protocols/tcp/tcp.h index c9d0255444..33640e55c5 100644 --- a/src/add-ons/kernel/network/protocols/tcp/tcp.h +++ b/src/add-ons/kernel/network/protocols/tcp/tcp.h @@ -157,17 +157,18 @@ enum tcp_segment_action { }; -extern net_domain *gDomain; -extern net_address_module_info *gAddressModule; extern net_buffer_module_info *gBufferModule; extern net_datalink_module_info *gDatalinkModule; extern net_socket_module_info *gSocketModule; extern net_stack_module_info *gStackModule; -extern EndpointManager *gEndpointManager; -status_t add_tcp_header(tcp_segment_header &segment, net_buffer *buffer); +status_t add_tcp_header(net_address_module_info *addressModule, + tcp_segment_header &segment, net_buffer *buffer); const char *name_for_state(tcp_state state); +EndpointManager *create_endpoint_manager(net_domain *domain); +void return_endpoint_manager(EndpointManager *); + #endif // TCP_H