From 6f440aed2ce4661713c3ac19a16bfdceaeccbeb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Fri, 24 Apr 2009 10:12:30 +0000 Subject: [PATCH] * net_socket_module_info::acquire_socket() now returns whether or not the socket could be acquired, ie. when its reference count is 0, it cannot be acquired anymore. This requires the protocol to do proper locking, though. * The TCP EndpointManager now checks the return value of acquire_socket(), and only returns the endpoint if that succeeded. * This fixes bug #2197. * Minor cleanup. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30363 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/net/net_socket.h | 2 +- .../kernel/network/protocols/tcp/EndpointManager.cpp | 12 ++++++------ .../kernel/network/protocols/tcp/TCPEndpoint.cpp | 4 ++-- src/add-ons/kernel/network/stack/net_socket.cpp | 11 ++++++++++- 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/headers/private/net/net_socket.h b/headers/private/net/net_socket.h index 12fe06b7a8..527d8ad27d 100644 --- a/headers/private/net/net_socket.h +++ b/headers/private/net/net_socket.h @@ -71,7 +71,7 @@ struct net_socket_module_info { struct net_stat *stat); // connections - void (*acquire_socket)(net_socket *socket); + bool (*acquire_socket)(net_socket *socket); bool (*release_socket)(net_socket *socket); status_t (*spawn_pending_socket)(net_socket *parent, diff --git a/src/add-ons/kernel/network/protocols/tcp/EndpointManager.cpp b/src/add-ons/kernel/network/protocols/tcp/EndpointManager.cpp index 27613ad03e..8420e334fe 100644 --- a/src/add-ons/kernel/network/protocols/tcp/EndpointManager.cpp +++ b/src/add-ons/kernel/network/protocols/tcp/EndpointManager.cpp @@ -320,8 +320,8 @@ EndpointManager::FindConnection(sockaddr* local, sockaddr* peer) if (endpoint != NULL) { TRACE(("TCP: Received packet corresponds to explicit endpoint %p\n", endpoint)); - gSocketModule->acquire_socket(endpoint->socket); - return endpoint; + if (gSocketModule->acquire_socket(endpoint->socket)) + return endpoint; } // no explicit endpoint exists, check for wildcard endpoints @@ -333,8 +333,8 @@ EndpointManager::FindConnection(sockaddr* local, sockaddr* peer) if (endpoint != NULL) { TRACE(("TCP: Received packet corresponds to wildcard endpoint %p\n", endpoint)); - gSocketModule->acquire_socket(endpoint->socket); - return endpoint; + if (gSocketModule->acquire_socket(endpoint->socket)) + return endpoint; } SocketAddressStorage localWildcard(AddressModule()); @@ -345,8 +345,8 @@ EndpointManager::FindConnection(sockaddr* local, sockaddr* peer) if (endpoint != NULL) { TRACE(("TCP: Received packet corresponds to local wildcard endpoint " "%p\n", endpoint)); - gSocketModule->acquire_socket(endpoint->socket); - return endpoint; + if (gSocketModule->acquire_socket(endpoint->socket)) + return endpoint; } // no matching endpoint exists diff --git a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp index 49a8c6462f..b79886708b 100644 --- a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp +++ b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp @@ -673,7 +673,7 @@ TCPEndpoint::Accept(struct net_socket** _acceptedSocket) status = acquire_sem_etc(fAcceptSemaphore, 1, B_ABSOLUTE_TIMEOUT | B_CAN_INTERRUPT, timeout); - if (status < B_OK) + if (status != B_OK) return status; locker.Lock(); @@ -682,7 +682,7 @@ TCPEndpoint::Accept(struct net_socket** _acceptedSocket) if (status == B_OK) TRACE(" Accept() returning %p", (*_acceptedSocket)->first_protocol); #endif - } while (status < B_OK); + } while (status != B_OK); return status; } diff --git a/src/add-ons/kernel/network/stack/net_socket.cpp b/src/add-ons/kernel/network/stack/net_socket.cpp index e9ddd3b197..786f4c534a 100644 --- a/src/add-ons/kernel/network/stack/net_socket.cpp +++ b/src/add-ons/kernel/network/stack/net_socket.cpp @@ -598,11 +598,20 @@ socket_get_next_stat(uint32* _cookie, int family, struct net_stat* stat) // #pragma mark - connections -void +bool socket_acquire(net_socket* _socket) { net_socket_private* socket = (net_socket_private*)_socket; + + // During destruction, the socket might still be accessible over its endpoint + // protocol. We need to make sure the endpoint cannot acquire the socket + // anymore -- while not obvious, the endpoint protocol is responsible for the + // proper locking here. + if (socket->CountReferences() == 0) + return false; + socket->AddReference(); + return true; }