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:
@@ -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> *
|
HashTableLink<TCPEndpoint> *
|
||||||
EndpointHashDefinition::GetLink(TCPEndpoint *endpoint) const
|
EndpointHashDefinition::GetLink(TCPEndpoint *endpoint) const
|
||||||
{
|
{
|
||||||
@@ -260,6 +268,34 @@ EndpointManager::_BindToAddress(TCPEndpoint *endpoint, const sockaddr *address)
|
|||||||
if (ntohs(port) <= kLastReservedPort && geteuid() != 0)
|
if (ntohs(port) <= kLastReservedPort && geteuid() != 0)
|
||||||
return B_PERMISSION_DENIED;
|
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);
|
return _Bind(endpoint, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,8 +320,7 @@ EndpointManager::_BindToEphemeral(TCPEndpoint *endpoint,
|
|||||||
|
|
||||||
port = htons(port);
|
port = htons(port);
|
||||||
|
|
||||||
TCPEndpoint *other = fEndpointHash.Lookup(port);
|
if (!fEndpointHash.Lookup(port).HasNext()) {
|
||||||
if (other == NULL) {
|
|
||||||
SocketAddressStorage newAddress(AddressModule());
|
SocketAddressStorage newAddress(AddressModule());
|
||||||
newAddress.SetTo(address);
|
newAddress.SetTo(address);
|
||||||
newAddress.SetPort(port);
|
newAddress.SetPort(port);
|
||||||
@@ -309,51 +344,13 @@ EndpointManager::_BindToEphemeral(TCPEndpoint *endpoint,
|
|||||||
status_t
|
status_t
|
||||||
EndpointManager::_Bind(TCPEndpoint *endpoint, const sockaddr *address)
|
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
|
// Thus far we have checked if the Bind() is allowed
|
||||||
|
|
||||||
status_t status = endpoint->next->module->bind(endpoint->next, address);
|
status_t status = endpoint->next->module->bind(endpoint->next, address);
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
endpoint->fEndpointNextWithSamePort = NULL;
|
fEndpointHash.Insert(endpoint);
|
||||||
|
|
||||||
if (insertionPoint)
|
|
||||||
insertionPoint->fEndpointNextWithSamePort = endpoint;
|
|
||||||
else
|
|
||||||
fEndpointHash.Insert(endpoint);
|
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
@@ -371,27 +368,11 @@ EndpointManager::Unbind(TCPEndpoint *endpoint)
|
|||||||
|
|
||||||
BenaphoreLocker _(fLock);
|
BenaphoreLocker _(fLock);
|
||||||
|
|
||||||
TCPEndpoint *other =
|
if (!fEndpointHash.Remove(endpoint)) {
|
||||||
fEndpointHash.Lookup(endpoint->LocalAddress().Port());
|
if (!endpoint->fSpawned)
|
||||||
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);
|
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);
|
fConnectionHash.Remove(endpoint);
|
||||||
|
|
||||||
(*endpoint->LocalAddress())->sa_len = 0;
|
(*endpoint->LocalAddress())->sa_len = 0;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
#include <lock.h>
|
#include <lock.h>
|
||||||
#include <util/DoublyLinkedList.h>
|
#include <util/DoublyLinkedList.h>
|
||||||
|
#include <util/MultiHashTable.h>
|
||||||
#include <util/OpenHashTable.h>
|
#include <util/OpenHashTable.h>
|
||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@@ -51,6 +52,7 @@ public:
|
|||||||
size_t HashKey(uint16 port) const;
|
size_t HashKey(uint16 port) const;
|
||||||
size_t Hash(TCPEndpoint *endpoint) const;
|
size_t Hash(TCPEndpoint *endpoint) const;
|
||||||
bool Compare(uint16 port, TCPEndpoint *endpoint) const;
|
bool Compare(uint16 port, TCPEndpoint *endpoint) const;
|
||||||
|
bool CompareValues(TCPEndpoint *first, TCPEndpoint *second) const;
|
||||||
HashTableLink<TCPEndpoint> *GetLink(TCPEndpoint *endpoint) const;
|
HashTableLink<TCPEndpoint> *GetLink(TCPEndpoint *endpoint) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -88,8 +90,11 @@ class EndpointManager : public DoublyLinkedListLinkImpl<EndpointManager> {
|
|||||||
|
|
||||||
net_domain *fDomain;
|
net_domain *fDomain;
|
||||||
|
|
||||||
OpenHashTable<ConnectionHashDefinition, true, true> fConnectionHash;
|
typedef OpenHashTable<ConnectionHashDefinition> ConnectionTable;
|
||||||
OpenHashTable<EndpointHashDefinition, true, true> fEndpointHash;
|
typedef MultiHashTable<EndpointHashDefinition> EndpointTable;
|
||||||
|
|
||||||
|
ConnectionTable fConnectionHash;
|
||||||
|
EndpointTable fEndpointHash;
|
||||||
benaphore fLock;
|
benaphore fLock;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -125,8 +125,6 @@ class TCPEndpoint : public net_protocol, public ProtocolSocket {
|
|||||||
friend class ConnectionHashDefinition;
|
friend class ConnectionHashDefinition;
|
||||||
friend class EndpointHashDefinition;
|
friend class EndpointHashDefinition;
|
||||||
|
|
||||||
TCPEndpoint *fEndpointNextWithSamePort;
|
|
||||||
|
|
||||||
recursive_lock fLock;
|
recursive_lock fLock;
|
||||||
WaitList fReceiveList;
|
WaitList fReceiveList;
|
||||||
WaitList fSendList;
|
WaitList fSendList;
|
||||||
|
|||||||
Reference in New Issue
Block a user