From 53f23f85a2725c8fc31c7a874256084c7c623d86 Mon Sep 17 00:00:00 2001 From: Hugo Santos Date: Wed, 25 Apr 2007 16:14:14 +0000 Subject: [PATCH] partially rewrote TCP's endpoint manager. Fixes #1173 git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20814 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/kernel/util/OpenHashTable.h | 18 +- headers/private/net/net_protocol.h | 2 +- .../kernel/network/protocols/icmp/icmp.cpp | 2 +- .../kernel/network/protocols/ipv4/ipv4.cpp | 2 +- .../network/protocols/tcp/EndpointManager.cpp | 429 ++++++++---------- .../network/protocols/tcp/EndpointManager.h | 57 ++- .../network/protocols/tcp/TCPEndpoint.cpp | 26 +- .../network/protocols/tcp/TCPEndpoint.h | 12 +- .../kernel/network/protocols/tcp/tcp.cpp | 3 +- .../kernel/network/protocols/udp/udp.cpp | 6 +- src/add-ons/kernel/network/stack/link.cpp | 2 +- 11 files changed, 284 insertions(+), 275 deletions(-) diff --git a/headers/private/kernel/util/OpenHashTable.h b/headers/private/kernel/util/OpenHashTable.h index a153da1655..6a0969ef9d 100644 --- a/headers/private/kernel/util/OpenHashTable.h +++ b/headers/private/kernel/util/OpenHashTable.h @@ -10,7 +10,7 @@ #ifndef _OPEN_HASH_TABLE_H_ #define _OPEN_HASH_TABLE_H_ -#include +#include // the Definition template must have three methods: `HashKey', `Hash' and // `Compare'. It must also define several types as shown in the following @@ -36,7 +36,7 @@ // is the same (property of the hash function) while not wasting one additional // word per item and having better cache locality. The usage of quadratic // probing reduces the effectiveness of cache locality but prevents clustering. -template +template class OpenHashTable { public: typedef typename Definition::ParentType ParentType; @@ -100,6 +100,13 @@ public: void InsertUnchecked(ValueType *value) { + if (CheckDuplicates) { + for (size_t i = 0; i < fTableSize; i++) { + if (fTable[i] == value) + panic("HashTable: item already in table"); + } + } + ValueType *previous = _Insert(fTable, fTableSize, value); if (_IsDeleted(previous)) fDeletedCount--; @@ -128,6 +135,13 @@ public: index = _NextSlot(f, index, fTableSize); } + if (CheckDuplicates) { + for (size_t i = 0; i < fTableSize; i++) { + if (fTable[i] == value) + panic("HashTable: item removed, but still in table."); + } + } + fItemCount--; fDeletedCount++; } diff --git a/headers/private/net/net_protocol.h b/headers/private/net/net_protocol.h index e51f06e16a..491b9799e1 100644 --- a/headers/private/net/net_protocol.h +++ b/headers/private/net/net_protocol.h @@ -41,7 +41,7 @@ struct net_protocol_module_info { status_t (*setsockopt)(net_protocol *self, int level, int option, const void *value, int length); - status_t (*bind)(net_protocol *self, struct sockaddr *address); + status_t (*bind)(net_protocol *self, const struct sockaddr *address); status_t (*unbind)(net_protocol *self, struct sockaddr *address); status_t (*listen)(net_protocol *self, int count); status_t (*shutdown)(net_protocol *self, int direction); diff --git a/src/add-ons/kernel/network/protocols/icmp/icmp.cpp b/src/add-ons/kernel/network/protocols/icmp/icmp.cpp index e02cf29688..6638dcceca 100644 --- a/src/add-ons/kernel/network/protocols/icmp/icmp.cpp +++ b/src/add-ons/kernel/network/protocols/icmp/icmp.cpp @@ -130,7 +130,7 @@ icmp_control(net_protocol *protocol, int level, int option, void *value, status_t -icmp_bind(net_protocol *protocol, struct sockaddr *address) +icmp_bind(net_protocol *protocol, const struct sockaddr *address) { return B_ERROR; } diff --git a/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp b/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp index 09987e5c0e..0474311324 100644 --- a/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp +++ b/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp @@ -1231,7 +1231,7 @@ ipv4_setsockopt(net_protocol *_protocol, int level, int option, status_t -ipv4_bind(net_protocol *protocol, struct sockaddr *address) +ipv4_bind(net_protocol *protocol, const struct sockaddr *address) { if (address->sa_family != AF_INET) return EAFNOSUPPORT; diff --git a/src/add-ons/kernel/network/protocols/tcp/EndpointManager.cpp b/src/add-ons/kernel/network/protocols/tcp/EndpointManager.cpp index 1ac15f779f..70b428b342 100644 --- a/src/add-ons/kernel/network/protocols/tcp/EndpointManager.cpp +++ b/src/add-ons/kernel/network/protocols/tcp/EndpointManager.cpp @@ -25,53 +25,79 @@ #endif -struct connection_key { - net_address_module_info *address_module; - const sockaddr *local; - const sockaddr *peer; -}; - -struct endpoint_key { - uint16 port; -}; - - -static const uint32 kConnectionHashBuckets = 256; -static const uint32 kEndpointHashBuckets = 256; - static const uint16 kLastReservedPort = 1023; static const uint16 kFirstEphemeralPort = 40000; -EndpointManager::EndpointManager(net_domain *domain) - : fDomain(domain) +size_t +ConnectionHashDefinition::HashKey(EndpointManager *manager, const KeyType &key) { - fConnectionHash = hash_init(kConnectionHashBuckets, - offsetof(TCPEndpoint, fConnectionHashNext), - &_ConnectionCompare, &_ConnectionHash); - fEndpointHash = hash_init(kEndpointHashBuckets, - offsetof(TCPEndpoint, fEndpointHashNext), - &_EndpointCompare, &_EndpointHash); + return manager->AddressModule()->hash_address_pair(key.first, key.second); +} - recursive_lock_init(&fLock, "endpoint manager"); + +size_t +ConnectionHashDefinition::Hash(EndpointManager *manager, TCPEndpoint *endpoint) +{ + return manager->AddressModule()->hash_address_pair( + endpoint->LocalAddress(), endpoint->PeerAddress()); +} + + +bool +ConnectionHashDefinition::Compare(EndpointManager *manager, const KeyType &key, + TCPEndpoint *endpoint) +{ + net_address_module_info *module = manager->AddressModule(); + + return module->equal_addresses_and_ports(key.first, endpoint->LocalAddress()) + && module->equal_addresses_and_ports(key.second, endpoint->PeerAddress()); +} + + +size_t +EndpointHashDefinition::HashKey(EndpointManager *manager, uint16 port) +{ + return port; +} + + +size_t +EndpointHashDefinition::Hash(EndpointManager *manager, TCPEndpoint *endpoint) +{ + return endpoint->AddressModule()->get_port(endpoint->LocalAddress()); +} + + +bool +EndpointHashDefinition::Compare(EndpointManager *manager, uint16 port, + TCPEndpoint *endpoint) +{ + return endpoint->AddressModule()->get_port(endpoint->LocalAddress()) == port; +} + + +EndpointManager::EndpointManager(net_domain *domain) + : fDomain(domain), fConnectionHash(this), fEndpointHash(this) +{ + benaphore_init(&fLock, "endpoint manager"); } EndpointManager::~EndpointManager() { - hash_uninit(fConnectionHash); - hash_uninit(fEndpointHash); - - recursive_lock_destroy(&fLock); + benaphore_destroy(&fLock); } status_t EndpointManager::InitCheck() const { - if (fConnectionHash == NULL - || fEndpointHash == NULL) - return B_NO_MEMORY; + if (fConnectionHash.InitCheck() < B_OK) + return fConnectionHash.InitCheck(); + + if (fEndpointHash.InitCheck() < B_OK) + return fEndpointHash.InitCheck(); if (fLock.sem < B_OK) return fLock.sem; @@ -88,43 +114,9 @@ EndpointManager::InitCheck() const You must hold the manager's lock when calling this method. */ TCPEndpoint * -EndpointManager::_LookupConnection(sockaddr *local, sockaddr *peer) +EndpointManager::_LookupConnection(const sockaddr *local, const sockaddr *peer) { - connection_key key; - key.address_module = AddressModule(); - key.local = local; - key.peer = peer; - - return (TCPEndpoint *)hash_lookup(fConnectionHash, &key); -} - - -status_t -EndpointManager::_RemoveConnection(TCPEndpoint *endpoint) -{ - RecursiveLocker locker(&fLock); - return hash_remove(fConnectionHash, endpoint); -} - - -void -EndpointManager::_DumpConnections() -{ - RecursiveLocker lock(&fLock); - - struct hash_iterator iterator; - hash_open(fConnectionHash, &iterator); - - TRACE(("Active TCP Connections:\n")); - - TCPEndpoint *endpoint; - while ((endpoint = (TCPEndpoint *)hash_next(fConnectionHash, &iterator)) != NULL) { - TRACE((" TCPEndpoint %p: local %s, peer %s\n", endpoint, - AddressString(Domain(), (sockaddr *)&endpoint->socket->address, true).Data(), - AddressString(Domain(), (sockaddr *)&endpoint->socket->peer, true).Data())); - } - - hash_close(fConnectionHash, &iterator, false); + return fConnectionHash.Lookup(std::make_pair(local, peer)); } @@ -134,7 +126,7 @@ EndpointManager::SetConnection(TCPEndpoint *endpoint, { TRACE(("EndpointManager::SetConnection(%p)\n", endpoint)); - RecursiveLocker locker(&fLock); + BenaphoreLocker _(fLock); sockaddr localBuffer; // need to associate this connection with a real address, not INADDR_ANY @@ -144,26 +136,54 @@ EndpointManager::SetConnection(TCPEndpoint *endpoint, local = &localBuffer; } - connection_key key; - key.address_module = AddressModule(); - key.local = local; - key.peer = peer; - - if (hash_lookup(fConnectionHash, &key) != NULL) + if (_LookupConnection(local, peer) != NULL) return EADDRINUSE; - _RemoveConnection(endpoint); + AddressModule()->set_to(endpoint->LocalAddress(), local); + AddressModule()->set_to(endpoint->PeerAddress(), peer); - AddressModule()->set_to((sockaddr *)&endpoint->socket->address, local); - AddressModule()->set_to((sockaddr *)&endpoint->socket->peer, peer); + if (!fConnectionHash.Insert(endpoint)) + return B_NO_MEMORY; - return hash_insert(fConnectionHash, endpoint); + return B_OK; +} + + +status_t +EndpointManager::SetPassive(TCPEndpoint *endpoint) +{ + BenaphoreLocker _(fLock); + + if (!endpoint->IsBound()) { + // if the socket is unbound first bind it to ephemeral + sockaddr_storage localAddress; + AddressModule()->set_to_empty_address((sockaddr *)&localAddress); + + status_t status = _BindToEphemeral(endpoint, + (sockaddr *)&localAddress); + if (status < B_OK) + return status; + } + + sockaddr_storage passive; + AddressModule()->set_to_empty_address((sockaddr *)&passive); + + if (_LookupConnection(endpoint->LocalAddress(), (sockaddr *)&passive)) + return EADDRINUSE; + + AddressModule()->set_to(endpoint->PeerAddress(), (sockaddr *)&passive); + if (!fConnectionHash.Insert(endpoint)) + return B_NO_MEMORY; + + return B_OK; } TCPEndpoint * EndpointManager::FindConnection(sockaddr *local, sockaddr *peer) { + BenaphoreLocker _(fLock); + TCPEndpoint *endpoint = _LookupConnection(local, peer); if (endpoint != NULL) { TRACE(("TCP: Received packet corresponds to explicit endpoint %p\n", endpoint)); @@ -193,7 +213,6 @@ EndpointManager::FindConnection(sockaddr *local, sockaddr *peer) // no matching endpoint exists TRACE(("TCP: no matching endpoint!\n")); - _DumpConnections(); return NULL; } @@ -202,81 +221,45 @@ EndpointManager::FindConnection(sockaddr *local, sockaddr *peer) // #pragma mark - endpoints -TCPEndpoint * -EndpointManager::_LookupEndpoint(uint16 port) +status_t +EndpointManager::Bind(TCPEndpoint *endpoint, const sockaddr *address) { - endpoint_key key; - key.port = port; + // TODO check the family: + // + // if (!AddressModule()->is_understandable(address)) + // return EAFNOSUPPORT; - return (TCPEndpoint *)hash_lookup(fEndpointHash, &key); + BenaphoreLocker _(fLock); + + if (AddressModule()->get_port(address) == 0) + return _BindToEphemeral(endpoint, address); + + return _BindToAddress(endpoint, address); } status_t -EndpointManager::Bind(TCPEndpoint *endpoint) +EndpointManager::_BindToAddress(TCPEndpoint *endpoint, const sockaddr *address) { - sockaddr *address = (sockaddr *)&endpoint->socket->address; - - TRACE(("EndpointManager::Bind(%p, %s)\n", endpoint, - AddressString(Domain(), address, true).Data())); - - if (AddressModule()->is_empty_address(address, true)) - return B_BAD_VALUE; + TRACE(("EndpointManager::BindToAddress(%p)\n", endpoint)); uint16 port = AddressModule()->get_port(address); - // TODO: check the root group instead? + // TODO this check follows very typical UNIX semantics + // and generally should be improved. if (ntohs(port) <= kLastReservedPort && geteuid() != 0) return B_PERMISSION_DENIED; - RecursiveLocker locker(&fLock); - - TCPEndpoint *first = _LookupEndpoint(port); - - // If there is already an endpoint bound to that port, SO_REUSEADDR has to be - // specified by the new endpoint to be allowed to bind to that same port. - // Alternatively, all endpoints must have the SO_REUSEPORT option set. - if (first != NULL - && (endpoint->socket->options & SO_REUSEADDR) == 0 - && ((endpoint->socket->options & SO_REUSEPORT) == 0 - || (first->socket->options & SO_REUSEPORT) == 0)) - return EADDRINUSE; - - if (first != NULL) { - TCPEndpoint *last = first; - while (true) { - // check if this endpoint binds to a wildcard address - 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; - } - - if (last->fEndpointNextWithSamePort == NULL) - break; - - last = last->fEndpointNextWithSamePort; - } - - // "first" stays the first item in the list - last->fEndpointNextWithSamePort = endpoint; - } else - hash_insert(fEndpointHash, endpoint); - - endpoint->fEndpointNextWithSamePort = NULL; - hash_insert(fConnectionHash, endpoint); - - return B_OK; + return _Bind(endpoint, address); } status_t -EndpointManager::BindToEphemeral(TCPEndpoint *endpoint) +EndpointManager::_BindToEphemeral(TCPEndpoint *endpoint, + const sockaddr *address) { TRACE(("EndpointManager::BindToEphemeral(%p)\n", endpoint)); - RecursiveLocker locker(&fLock); - uint32 max = kFirstEphemeralPort + 65536; for (int32 i = 1; i < 5; i++) { @@ -291,16 +274,17 @@ EndpointManager::BindToEphemeral(TCPEndpoint *endpoint) port = htons(port); - TCPEndpoint *other = _LookupEndpoint(port); + TCPEndpoint *other = fEndpointHash.Lookup(port); if (other == NULL) { + sockaddr_storage newAddress; + AddressModule()->set_to((sockaddr *)&newAddress, address); + AddressModule()->set_port((sockaddr *)&newAddress, port); + // found a port - AddressModule()->set_port((sockaddr *)&endpoint->socket->address, port); TRACE((" EndpointManager::BindToEphemeral(%p) -> %s\n", endpoint, - AddressString(Domain(), (sockaddr *)&endpoint->socket->address, true).Data())); - endpoint->fEndpointNextWithSamePort = NULL; - hash_insert(fEndpointHash, endpoint); - hash_insert(fConnectionHash, endpoint); - return B_OK; + AddressString(Domain(), (sockaddr *)&newAddress, true).Data())); + + return _Bind(endpoint, (sockaddr *)&newAddress); } counter += step; @@ -313,38 +297,92 @@ EndpointManager::BindToEphemeral(TCPEndpoint *endpoint) status_t -EndpointManager::Unbind(TCPEndpoint *endpoint) +EndpointManager::_Bind(TCPEndpoint *endpoint, const sockaddr *address) { - if (endpoint == NULL || !endpoint->IsBound()) - return B_BAD_VALUE; + uint16 port = AddressModule()->get_port(address); - RecursiveLocker locker(&fLock); + TCPEndpoint *first = fEndpointHash.Lookup(port); - if (!endpoint->fSpawned) { - TCPEndpoint *other = _LookupEndpoint(AddressModule()->get_port( - (sockaddr *)&endpoint->socket->address)); - if (other != endpoint) { - // remove endpoint from the list of endpoints with the same port - while (other != NULL && other->fEndpointNextWithSamePort != endpoint) { - other = other->fEndpointNextWithSamePort; + // If there is already an endpoint bound to that port, SO_REUSEADDR has to be + // specified by the new endpoint to be allowed to bind to that same port. + // Alternatively, all endpoints must have the SO_REUSEPORT option set. + if (first != NULL + && (endpoint->socket->options & SO_REUSEADDR) == 0 + && ((endpoint->socket->options & SO_REUSEPORT) == 0 + || (first->socket->options & SO_REUSEPORT) == 0)) + return EADDRINUSE; + + TCPEndpoint *insertionPoint = NULL; + + if (first != NULL) { + while (true) { + // check if this endpoint binds to a wildcard address + if (AddressModule()->is_empty_address(first->LocalAddress(), false)) { + // you cannot specialize a wildcard endpoint - you have to open the + // wildcard endpoint last + return B_PERMISSION_DENIED; } - if (other != NULL) - other->fEndpointNextWithSamePort = endpoint->fEndpointNextWithSamePort; - else - panic("bound endpoint %p not in hash!", endpoint); - } else { - // we need to replace the first endpoint in the list - hash_remove(fEndpointHash, endpoint); + if (first->fEndpointNextWithSamePort == NULL) + break; - other = endpoint->fEndpointNextWithSamePort; - if (other != NULL) - hash_insert(fEndpointHash, other); + first = first->fEndpointNextWithSamePort; } + + insertionPoint = first; + } + + // Thus far we have checked if the Bind() is allowed + + status_t status = endpoint->next->module->bind(endpoint->next, address); + if (status < B_OK) + return status; + + endpoint->fEndpointNextWithSamePort = NULL; + + if (insertionPoint) + insertionPoint->fEndpointNextWithSamePort = endpoint; + else + fEndpointHash.Insert(endpoint); + + return B_OK; +} + + +status_t +EndpointManager::Unbind(TCPEndpoint *endpoint) +{ + TRACE(("EndpointManager::Unbind(%p)\n", endpoint)); + + if (endpoint == NULL || !endpoint->IsBound()) { + TRACE((" endpoint is unbound.\n")); + return B_BAD_VALUE; + } + + BenaphoreLocker _(fLock); + + TCPEndpoint *other = fEndpointHash.Lookup( + AddressModule()->get_port(endpoint->LocalAddress())); + if (other != endpoint) { + // remove endpoint from the list of endpoints with the same port + while (other != NULL && other->fEndpointNextWithSamePort != endpoint) + other = other->fEndpointNextWithSamePort; + + if (other != NULL) + other->fEndpointNextWithSamePort = endpoint->fEndpointNextWithSamePort; + else if (!endpoint->fSpawned) + panic("bound endpoint %p not in hash!", endpoint); + } else { + // we need to replace the first endpoint in the list + fEndpointHash.Remove(endpoint); + + other = endpoint->fEndpointNextWithSamePort; + if (other != NULL) + fEndpointHash.Insert(other); } endpoint->fEndpointNextWithSamePort = NULL; - _RemoveConnection(endpoint); + fConnectionHash.Remove(endpoint); endpoint->socket->address.ss_len = 0; @@ -389,70 +427,3 @@ EndpointManager::ReplyWithReset(tcp_segment_header &segment, return status; } - -// #pragma mark - hash functions - - -/*static*/ int -EndpointManager::_ConnectionCompare(void *_endpoint, const void *_key) -{ - const connection_key *key = (connection_key *)_key; - TCPEndpoint *endpoint = (TCPEndpoint *)_endpoint; - - if (key->address_module->equal_addresses_and_ports(key->local, - (sockaddr *)&endpoint->socket->address) - && key->address_module->equal_addresses_and_ports(key->peer, - (sockaddr *)&endpoint->socket->peer)) - return 0; - - return 1; -} - - -/*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 address_module->hash_address_pair(local, peer) % range; -} - - -/*static*/ int -EndpointManager::_EndpointCompare(void *_endpoint, const void *_key) -{ - const endpoint_key *key = (endpoint_key *)_key; - TCPEndpoint *endpoint = (TCPEndpoint *)_endpoint; - - return endpoint->AddressModule()->get_port( - (sockaddr *)&endpoint->socket->address) == key->port ? 0 : 1; -} - - -/*static*/ uint32 -EndpointManager::_EndpointHash(void *_endpoint, const void *_key, uint32 range) -{ - if (_endpoint != NULL) { - TCPEndpoint *endpoint = (TCPEndpoint *)_endpoint; - return endpoint->AddressModule()->get_port( - (sockaddr *)&endpoint->socket->address) % range; - } - - const endpoint_key *key = (endpoint_key *)_key; - return key->port % range; -} - diff --git a/src/add-ons/kernel/network/protocols/tcp/EndpointManager.h b/src/add-ons/kernel/network/protocols/tcp/EndpointManager.h index b4844aaf67..c881e6481c 100644 --- a/src/add-ons/kernel/network/protocols/tcp/EndpointManager.h +++ b/src/add-ons/kernel/network/protocols/tcp/EndpointManager.h @@ -14,15 +14,42 @@ #include #include -#include +#include #include +#include + struct net_address_module_info; struct net_domain; +class EndpointManager; class TCPEndpoint; +struct ConnectionHashDefinition { + typedef EndpointManager *ParentType; + typedef std::pair KeyType; + typedef TCPEndpoint ValueType; + + static size_t HashKey(EndpointManager *manager, const KeyType &key); + static size_t Hash(EndpointManager *manager, TCPEndpoint *endpoint); + static bool Compare(EndpointManager *manager, const KeyType &key, + TCPEndpoint *endpoint); +}; + + +struct EndpointHashDefinition { + typedef EndpointManager *ParentType; + typedef uint16 KeyType; + typedef TCPEndpoint ValueType; + + static size_t HashKey(EndpointManager *manager, uint16 port); + static size_t Hash(EndpointManager *manager, TCPEndpoint *endpoint); + static bool Compare(EndpointManager *manager, uint16 port, + TCPEndpoint *endpoint); +}; + + class EndpointManager : public DoublyLinkedListLinkImpl { public: EndpointManager(net_domain *domain); @@ -30,14 +57,13 @@ class EndpointManager : public DoublyLinkedListLinkImpl { status_t InitCheck() const; - recursive_lock *Locker() { return &fLock; } + TCPEndpoint *FindConnection(sockaddr *local, sockaddr *peer); status_t SetConnection(TCPEndpoint *endpoint, const sockaddr *local, const sockaddr *peer, const sockaddr *interfaceLocal); - TCPEndpoint *FindConnection(sockaddr *local, sockaddr *peer); + status_t SetPassive(TCPEndpoint *endpoint); - status_t Bind(TCPEndpoint *endpoint); - status_t BindToEphemeral(TCPEndpoint *endpoint); + status_t Bind(TCPEndpoint *endpoint, const sockaddr *address); status_t Unbind(TCPEndpoint *endpoint); status_t ReplyWithReset(tcp_segment_header &segment, @@ -48,21 +74,18 @@ class EndpointManager : public DoublyLinkedListLinkImpl { { return Domain()->address_module; } private: - TCPEndpoint *_LookupConnection(sockaddr *local, sockaddr *peer); - status_t _RemoveConnection(TCPEndpoint *endpoint); - TCPEndpoint *_LookupEndpoint(uint16 port); - void _DumpConnections(); - - static int _ConnectionCompare(void *_endpoint, const void *_key); - static uint32 _ConnectionHash(void *_endpoint, const void *_key, uint32 range); - static int _EndpointCompare(void *_endpoint, const void *_key); - static uint32 _EndpointHash(void *_endpoint, const void *_key, uint32 range); + TCPEndpoint *_LookupConnection(const sockaddr *local, + const sockaddr *peer); + status_t _Bind(TCPEndpoint *endpoint, const sockaddr *address); + status_t _BindToAddress(TCPEndpoint *endpoint, const sockaddr *address); + status_t _BindToEphemeral(TCPEndpoint *endpoint, + const sockaddr *address); net_domain *fDomain; - hash_table *fConnectionHash; - hash_table *fEndpointHash; - recursive_lock fLock; + OpenHashTable fConnectionHash; + OpenHashTable fEndpointHash; + benaphore fLock; }; #endif // ENDPOINT_MANAGER_H diff --git a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp index 9508b09087..d5f0128002 100644 --- a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp +++ b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp @@ -450,7 +450,7 @@ TCPEndpoint::Accept(struct net_socket **_acceptedSocket) status_t -TCPEndpoint::Bind(sockaddr *address) +TCPEndpoint::Bind(const sockaddr *address) { if (address == NULL) return B_BAD_VALUE; @@ -462,20 +462,7 @@ TCPEndpoint::Bind(sockaddr *address) if (fState != CLOSED) return EISCONN; - // 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; - - if (AddressModule()->get_port(address) == 0) - status = fManager->BindToEphemeral(this); - else - status = fManager->Bind(this); - - TRACE(" Bind() bound to %s (status %i)", PrintAddress(&socket->address), - (int)status); - - return status; + return fManager->Bind(this, address); } @@ -498,13 +485,18 @@ TCPEndpoint::Listen(int count) if (fState != CLOSED) return B_BAD_VALUE; - if (!IsBound()) - return EDESTADDRREQ; fAcceptSemaphore = create_sem(0, "tcp accept"); if (fAcceptSemaphore < B_OK) return ENOBUFS; + status_t status = fManager->SetPassive(this); + if (status < B_OK) { + delete_sem(fAcceptSemaphore); + fAcceptSemaphore = -1; + return status; + } + fState = LISTEN; return B_OK; } diff --git a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h index 50bd9db68f..d5c6c83090 100644 --- a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h +++ b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h @@ -50,7 +50,7 @@ class TCPEndpoint : public net_protocol { 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 Bind(const sockaddr *address); status_t Unbind(struct sockaddr *address); status_t Listen(int count); status_t Shutdown(int direction); @@ -65,6 +65,16 @@ class TCPEndpoint : public net_protocol { tcp_state State() const { return fState; } bool IsBound() const; + const sockaddr *LocalAddress() const + { return (sockaddr *)&socket->address; } + sockaddr *LocalAddress() + { return (sockaddr *)&socket->address; } + + const sockaddr *PeerAddress() const + { return (sockaddr *)&socket->peer; } + sockaddr *PeerAddress() + { return (sockaddr *)&socket->peer; } + void DeleteSocket(); status_t DelayedAcknowledge(); diff --git a/src/add-ons/kernel/network/protocols/tcp/tcp.cpp b/src/add-ons/kernel/network/protocols/tcp/tcp.cpp index 688c6d426e..71ee0d2159 100644 --- a/src/add-ons/kernel/network/protocols/tcp/tcp.cpp +++ b/src/add-ons/kernel/network/protocols/tcp/tcp.cpp @@ -500,7 +500,7 @@ tcp_setsockopt(net_protocol *_protocol, int level, int option, status_t -tcp_bind(net_protocol *protocol, struct sockaddr *address) +tcp_bind(net_protocol *protocol, const struct sockaddr *address) { return ((TCPEndpoint *)protocol)->Bind(address); } @@ -630,7 +630,6 @@ tcp_receive_data(net_buffer *buffer) if (endpointManager == NULL) return B_ERROR; - RecursiveLocker locker(endpointManager->Locker()); int32 segmentAction = DROP; TCPEndpoint *endpoint = endpointManager->FindConnection( diff --git a/src/add-ons/kernel/network/protocols/udp/udp.cpp b/src/add-ons/kernel/network/protocols/udp/udp.cpp index 07ba62ba76..4f6336b1a1 100644 --- a/src/add-ons/kernel/network/protocols/udp/udp.cpp +++ b/src/add-ons/kernel/network/protocols/udp/udp.cpp @@ -66,7 +66,7 @@ class UdpEndpoint : public net_protocol, public DatagramSocket<> { public: UdpEndpoint(net_socket *socket); - status_t Bind(sockaddr *newAddr); + status_t Bind(const sockaddr *newAddr); status_t Unbind(sockaddr *newAddr); status_t Connect(const sockaddr *newAddr); @@ -711,7 +711,7 @@ UdpEndpoint::UdpEndpoint(net_socket *socket) status_t -UdpEndpoint::Bind(sockaddr *address) +UdpEndpoint::Bind(const sockaddr *address) { TRACE_EP("Bind(%s)", AddressString(Domain(), address, true).Data()); @@ -1021,7 +1021,7 @@ udp_control(net_protocol *protocol, int level, int option, void *value, status_t -udp_bind(net_protocol *protocol, struct sockaddr *address) +udp_bind(net_protocol *protocol, const struct sockaddr *address) { return ((UdpEndpoint *)protocol)->Bind(address); } diff --git a/src/add-ons/kernel/network/stack/link.cpp b/src/add-ons/kernel/network/stack/link.cpp index a8b4b16d85..3e5d408f4e 100644 --- a/src/add-ons/kernel/network/stack/link.cpp +++ b/src/add-ons/kernel/network/stack/link.cpp @@ -320,7 +320,7 @@ link_control(net_protocol *_protocol, int level, int option, void *value, status_t -link_bind(net_protocol *protocol, struct sockaddr *address) +link_bind(net_protocol *protocol, const struct sockaddr *address) { // TODO: bind to a specific interface and ethernet type return B_ERROR;