From 342444bc95a45142c5e6fa824c96ca1c1343c84f Mon Sep 17 00:00:00 2001 From: Hugo Santos Date: Fri, 27 Apr 2007 15:06:41 +0000 Subject: [PATCH] replaced TCP's Endpoint Manager manual handling of endpoint lists with MultiHashTable. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20865 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../network/protocols/tcp/EndpointManager.cpp | 99 ++++++++----------- .../network/protocols/tcp/EndpointManager.h | 9 +- .../network/protocols/tcp/TCPEndpoint.h | 2 - 3 files changed, 47 insertions(+), 63 deletions(-) diff --git a/src/add-ons/kernel/network/protocols/tcp/EndpointManager.cpp b/src/add-ons/kernel/network/protocols/tcp/EndpointManager.cpp index b5ade2c051..ca191021aa 100644 --- a/src/add-ons/kernel/network/protocols/tcp/EndpointManager.cpp +++ b/src/add-ons/kernel/network/protocols/tcp/EndpointManager.cpp @@ -84,6 +84,14 @@ EndpointHashDefinition::Compare(uint16 port, TCPEndpoint *endpoint) const } +bool +EndpointHashDefinition::CompareValues(TCPEndpoint *first, + TCPEndpoint *second) const +{ + return first->LocalAddress().Port() == second->LocalAddress().Port(); +} + + HashTableLink * EndpointHashDefinition::GetLink(TCPEndpoint *endpoint) const { @@ -260,6 +268,34 @@ EndpointManager::_BindToAddress(TCPEndpoint *endpoint, const sockaddr *address) if (ntohs(port) <= kLastReservedPort && geteuid() != 0) return B_PERMISSION_DENIED; + EndpointTable::Iterator portUsers = fEndpointHash.Lookup(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 (portUsers.HasNext()) { + TCPEndpoint *user = portUsers.Next(); + + if ((endpoint->socket->options & SO_REUSEADDR) == 0 + && ((endpoint->socket->options & SO_REUSEPORT) == 0 + || (user->socket->options & SO_REUSEPORT) == 0)) + return EADDRINUSE; + + do { + // check if this endpoint binds to a wildcard address + if (user->LocalAddress().IsEmpty(false)) { + // you cannot specialize a wildcard endpoint - you have to open + // the wildcard endpoint last + return B_PERMISSION_DENIED; + } + + if (portUsers.HasNext()) + user = portUsers.Next(); + else + break; + } while (true); + } + return _Bind(endpoint, address); } @@ -284,8 +320,7 @@ EndpointManager::_BindToEphemeral(TCPEndpoint *endpoint, port = htons(port); - TCPEndpoint *other = fEndpointHash.Lookup(port); - if (other == NULL) { + if (!fEndpointHash.Lookup(port).HasNext()) { SocketAddressStorage newAddress(AddressModule()); newAddress.SetTo(address); newAddress.SetPort(port); @@ -309,51 +344,13 @@ EndpointManager::_BindToEphemeral(TCPEndpoint *endpoint, status_t EndpointManager::_Bind(TCPEndpoint *endpoint, const sockaddr *address) { - uint16 port = AddressModule()->get_port(address); - - TCPEndpoint *first = fEndpointHash.Lookup(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; - - TCPEndpoint *insertionPoint = NULL; - - if (first != NULL) { - while (true) { - // check if this endpoint binds to a wildcard address - if (first->LocalAddress().IsEmpty(false)) { - // you cannot specialize a wildcard endpoint - you have to open - // the wildcard endpoint last - return B_PERMISSION_DENIED; - } - - if (first->fEndpointNextWithSamePort == NULL) - break; - - 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); + fEndpointHash.Insert(endpoint); return B_OK; } @@ -371,27 +368,11 @@ EndpointManager::Unbind(TCPEndpoint *endpoint) BenaphoreLocker _(fLock); - TCPEndpoint *other = - fEndpointHash.Lookup(endpoint->LocalAddress().Port()); - 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) + if (!fEndpointHash.Remove(endpoint)) { + 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; fConnectionHash.Remove(endpoint); (*endpoint->LocalAddress())->sa_len = 0; diff --git a/src/add-ons/kernel/network/protocols/tcp/EndpointManager.h b/src/add-ons/kernel/network/protocols/tcp/EndpointManager.h index 0aa1f9cd27..6b485d6e4c 100644 --- a/src/add-ons/kernel/network/protocols/tcp/EndpointManager.h +++ b/src/add-ons/kernel/network/protocols/tcp/EndpointManager.h @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -51,6 +52,7 @@ public: size_t HashKey(uint16 port) const; size_t Hash(TCPEndpoint *endpoint) const; bool Compare(uint16 port, TCPEndpoint *endpoint) const; + bool CompareValues(TCPEndpoint *first, TCPEndpoint *second) const; HashTableLink *GetLink(TCPEndpoint *endpoint) const; }; @@ -88,8 +90,11 @@ class EndpointManager : public DoublyLinkedListLinkImpl { net_domain *fDomain; - OpenHashTable fConnectionHash; - OpenHashTable fEndpointHash; + typedef OpenHashTable ConnectionTable; + typedef MultiHashTable EndpointTable; + + ConnectionTable fConnectionHash; + EndpointTable fEndpointHash; benaphore fLock; }; diff --git a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h index a4c9a99fbc..bf3bca9706 100644 --- a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h +++ b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.h @@ -125,8 +125,6 @@ class TCPEndpoint : public net_protocol, public ProtocolSocket { friend class ConnectionHashDefinition; friend class EndpointHashDefinition; - TCPEndpoint *fEndpointNextWithSamePort; - recursive_lock fLock; WaitList fReceiveList; WaitList fSendList;