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:
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user