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:
parent
342444bc95
commit
9cd3b980fd
@ -257,11 +257,21 @@ EndpointManager::Bind(TCPEndpoint *endpoint, const sockaddr *address)
|
||||
|
||||
|
||||
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));
|
||||
|
||||
uint16 port = AddressModule()->get_port(address);
|
||||
ConstSocketAddress address(AddressModule(), _address);
|
||||
|
||||
uint16 port = address.Port();
|
||||
|
||||
// TODO this check follows very typical UNIX semantics
|
||||
// and generally should be improved.
|
||||
@ -270,33 +280,20 @@ EndpointManager::_BindToAddress(TCPEndpoint *endpoint, const sockaddr *address)
|
||||
|
||||
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()) {
|
||||
while (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);
|
||||
if (user->LocalAddress().IsEmpty(false)
|
||||
|| address.EqualTo(*user->LocalAddress(), false)) {
|
||||
if ((endpoint->socket->options & SO_REUSEADDR) == 0)
|
||||
return EADDRINUSE;
|
||||
// TODO lock endpoint before retriving state?
|
||||
if (user->State() != TIME_WAIT && user->State() != CLOSED)
|
||||
return EADDRINUSE;
|
||||
}
|
||||
}
|
||||
|
||||
return _Bind(endpoint, address);
|
||||
return _Bind(endpoint, *address);
|
||||
}
|
||||
|
||||
|
||||
@ -368,10 +365,8 @@ EndpointManager::Unbind(TCPEndpoint *endpoint)
|
||||
|
||||
BenaphoreLocker _(fLock);
|
||||
|
||||
if (!fEndpointHash.Remove(endpoint)) {
|
||||
if (!endpoint->fSpawned)
|
||||
panic("bound endpoint %p not in hash!", endpoint);
|
||||
}
|
||||
if (!fEndpointHash.Remove(endpoint))
|
||||
panic("bound endpoint %p not in hash!", endpoint);
|
||||
|
||||
fConnectionHash.Remove(endpoint);
|
||||
|
||||
|
@ -71,6 +71,7 @@ class EndpointManager : public DoublyLinkedListLinkImpl<EndpointManager> {
|
||||
status_t SetPassive(TCPEndpoint *endpoint);
|
||||
|
||||
status_t Bind(TCPEndpoint *endpoint, const sockaddr *address);
|
||||
status_t BindChild(TCPEndpoint *endpoint);
|
||||
status_t Unbind(TCPEndpoint *endpoint);
|
||||
|
||||
status_t ReplyWithReset(tcp_segment_header &segment,
|
||||
|
@ -241,8 +241,7 @@ TCPEndpoint::TCPEndpoint(net_socket *socket)
|
||||
fSlowStartThreshold(0),
|
||||
fState(CLOSED),
|
||||
fFlags(FLAG_OPTION_WINDOW_SCALE | FLAG_OPTION_TIMESTAMP),
|
||||
fError(B_OK),
|
||||
fSpawned(false)
|
||||
fError(B_OK)
|
||||
{
|
||||
//gStackModule->init_timer(&fTimer, _TimeWait, this);
|
||||
|
||||
@ -823,7 +822,6 @@ TCPEndpoint::Spawn(TCPEndpoint *parent, tcp_segment_header &segment,
|
||||
|
||||
fState = SYNCHRONIZE_RECEIVED;
|
||||
fManager = parent->fManager;
|
||||
fSpawned = true;
|
||||
|
||||
LocalAddress().SetTo(&buffer->destination);
|
||||
PeerAddress().SetTo(&buffer->source);
|
||||
@ -831,6 +829,9 @@ TCPEndpoint::Spawn(TCPEndpoint *parent, tcp_segment_header &segment,
|
||||
TRACE("Spawn()");
|
||||
|
||||
// TODO: proper error handling!
|
||||
if (fManager->BindChild(this) < B_OK)
|
||||
return DROP;
|
||||
|
||||
if (_PrepareSendPath(*PeerAddress()) < B_OK)
|
||||
return DROP;
|
||||
|
||||
|
@ -169,8 +169,6 @@ class TCPEndpoint : public net_protocol, public ProtocolSocket {
|
||||
uint32 fFlags;
|
||||
status_t fError;
|
||||
|
||||
bool fSpawned;
|
||||
|
||||
// timer
|
||||
net_timer fRetransmitTimer;
|
||||
net_timer fPersistTimer;
|
||||
|
Loading…
Reference in New Issue
Block a user