fixed a long standing binding issue with spawned sockets and TCP. also fixed bind() address checking rules.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20866 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Hugo Santos
2007-04-27 15:49:00 +00:00
parent 342444bc95
commit 9cd3b980fd
4 changed files with 29 additions and 34 deletions
@@ -257,11 +257,21 @@ EndpointManager::Bind(TCPEndpoint *endpoint, const sockaddr *address)
status_t status_t
EndpointManager::_BindToAddress(TCPEndpoint *endpoint, const sockaddr *address) EndpointManager::BindChild(TCPEndpoint *endpoint)
{
BenaphoreLocker _(fLock);
return _Bind(endpoint, *endpoint->LocalAddress());
}
status_t
EndpointManager::_BindToAddress(TCPEndpoint *endpoint, const sockaddr *_address)
{ {
TRACE(("EndpointManager::BindToAddress(%p)\n", endpoint)); TRACE(("EndpointManager::BindToAddress(%p)\n", endpoint));
uint16 port = AddressModule()->get_port(address); ConstSocketAddress address(AddressModule(), _address);
uint16 port = address.Port();
// TODO this check follows very typical UNIX semantics // TODO this check follows very typical UNIX semantics
// and generally should be improved. // and generally should be improved.
@@ -270,33 +280,20 @@ EndpointManager::_BindToAddress(TCPEndpoint *endpoint, const sockaddr *address)
EndpointTable::Iterator portUsers = fEndpointHash.Lookup(port); EndpointTable::Iterator portUsers = fEndpointHash.Lookup(port);
// If there is already an endpoint bound to that port, SO_REUSEADDR has to be while (portUsers.HasNext()) {
// 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(); TCPEndpoint *user = portUsers.Next();
if ((endpoint->socket->options & SO_REUSEADDR) == 0 if (user->LocalAddress().IsEmpty(false)
&& ((endpoint->socket->options & SO_REUSEPORT) == 0 || address.EqualTo(*user->LocalAddress(), false)) {
|| (user->socket->options & SO_REUSEPORT) == 0)) if ((endpoint->socket->options & SO_REUSEADDR) == 0)
return EADDRINUSE; return EADDRINUSE;
// TODO lock endpoint before retriving state?
do { if (user->State() != TIME_WAIT && user->State() != CLOSED)
// check if this endpoint binds to a wildcard address return EADDRINUSE;
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);
} }
@@ -368,10 +365,8 @@ EndpointManager::Unbind(TCPEndpoint *endpoint)
BenaphoreLocker _(fLock); BenaphoreLocker _(fLock);
if (!fEndpointHash.Remove(endpoint)) { if (!fEndpointHash.Remove(endpoint))
if (!endpoint->fSpawned) panic("bound endpoint %p not in hash!", endpoint);
panic("bound endpoint %p not in hash!", endpoint);
}
fConnectionHash.Remove(endpoint); fConnectionHash.Remove(endpoint);
@@ -71,6 +71,7 @@ class EndpointManager : public DoublyLinkedListLinkImpl<EndpointManager> {
status_t SetPassive(TCPEndpoint *endpoint); status_t SetPassive(TCPEndpoint *endpoint);
status_t Bind(TCPEndpoint *endpoint, const sockaddr *address); status_t Bind(TCPEndpoint *endpoint, const sockaddr *address);
status_t BindChild(TCPEndpoint *endpoint);
status_t Unbind(TCPEndpoint *endpoint); status_t Unbind(TCPEndpoint *endpoint);
status_t ReplyWithReset(tcp_segment_header &segment, status_t ReplyWithReset(tcp_segment_header &segment,
@@ -241,8 +241,7 @@ TCPEndpoint::TCPEndpoint(net_socket *socket)
fSlowStartThreshold(0), fSlowStartThreshold(0),
fState(CLOSED), fState(CLOSED),
fFlags(FLAG_OPTION_WINDOW_SCALE | FLAG_OPTION_TIMESTAMP), fFlags(FLAG_OPTION_WINDOW_SCALE | FLAG_OPTION_TIMESTAMP),
fError(B_OK), fError(B_OK)
fSpawned(false)
{ {
//gStackModule->init_timer(&fTimer, _TimeWait, this); //gStackModule->init_timer(&fTimer, _TimeWait, this);
@@ -823,7 +822,6 @@ TCPEndpoint::Spawn(TCPEndpoint *parent, tcp_segment_header &segment,
fState = SYNCHRONIZE_RECEIVED; fState = SYNCHRONIZE_RECEIVED;
fManager = parent->fManager; fManager = parent->fManager;
fSpawned = true;
LocalAddress().SetTo(&buffer->destination); LocalAddress().SetTo(&buffer->destination);
PeerAddress().SetTo(&buffer->source); PeerAddress().SetTo(&buffer->source);
@@ -831,6 +829,9 @@ TCPEndpoint::Spawn(TCPEndpoint *parent, tcp_segment_header &segment,
TRACE("Spawn()"); TRACE("Spawn()");
// TODO: proper error handling! // TODO: proper error handling!
if (fManager->BindChild(this) < B_OK)
return DROP;
if (_PrepareSendPath(*PeerAddress()) < B_OK) if (_PrepareSendPath(*PeerAddress()) < B_OK)
return DROP; return DROP;
@@ -169,8 +169,6 @@ class TCPEndpoint : public net_protocol, public ProtocolSocket {
uint32 fFlags; uint32 fFlags;
status_t fError; status_t fError;
bool fSpawned;
// timer // timer
net_timer fRetransmitTimer; net_timer fRetransmitTimer;
net_timer fPersistTimer; net_timer fPersistTimer;