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
This commit is contained in:
Hugo Santos 2007-04-27 15:06:41 +00:00
parent 505e98538a
commit 342444bc95
3 changed files with 47 additions and 63 deletions

View File

@ -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<TCPEndpoint> *
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;

View File

@ -14,6 +14,7 @@
#include <lock.h>
#include <util/DoublyLinkedList.h>
#include <util/MultiHashTable.h>
#include <util/OpenHashTable.h>
#include <utility>
@ -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<TCPEndpoint> *GetLink(TCPEndpoint *endpoint) const;
};
@ -88,8 +90,11 @@ class EndpointManager : public DoublyLinkedListLinkImpl<EndpointManager> {
net_domain *fDomain;
OpenHashTable<ConnectionHashDefinition, true, true> fConnectionHash;
OpenHashTable<EndpointHashDefinition, true, true> fEndpointHash;
typedef OpenHashTable<ConnectionHashDefinition> ConnectionTable;
typedef MultiHashTable<EndpointHashDefinition> EndpointTable;
ConnectionTable fConnectionHash;
EndpointTable fEndpointHash;
benaphore fLock;
};

View File

@ -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;