Rewrote how bind() works:
* there are now two hash tables: one for connections, and one for ports * the first one is used to find the endpoint for incoming connections * the latter is used to check if the address to bind() to is still available (incl. support for SO_REUSEADDR, and SO_REUSEPORT). Specialising an existing socket is not allowed, though; wildcard sockets need to be started last. * the TCPConnection class now has a pointer to the next endpoint with the same port number - this list is scanned for the existing bound sockets on that port. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@19416 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -0,0 +1,400 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2006, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Axel Dörfler, [email protected]
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "EndpointManager.h"
|
||||||
|
#include "TCPConnection.h"
|
||||||
|
|
||||||
|
#include <NetUtilities.h>
|
||||||
|
|
||||||
|
#include <util/AutoLock.h>
|
||||||
|
|
||||||
|
#include <KernelExport.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define TRACE_ENDPOINT_MANAGER
|
||||||
|
#ifdef TRACE_ENDPOINT_MANAGER
|
||||||
|
# define TRACE(x) dprintf x
|
||||||
|
#else
|
||||||
|
# define TRACE(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
struct connection_key {
|
||||||
|
const sockaddr *local;
|
||||||
|
const sockaddr *peer;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct endpoint_key {
|
||||||
|
uint16 port;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static const uint32 kConnectionHashBuckets = 256;
|
||||||
|
static const uint32 kEndpointHashBuckets = 256;
|
||||||
|
|
||||||
|
static const uint16 kLastReservedPort = 1023;
|
||||||
|
static const uint16 kFirstEphemeralPort = 40000;
|
||||||
|
|
||||||
|
|
||||||
|
EndpointManager::EndpointManager()
|
||||||
|
{
|
||||||
|
fConnectionHash = hash_init(kConnectionHashBuckets,
|
||||||
|
offsetof(TCPConnection, fConnectionHashNext),
|
||||||
|
&_ConnectionCompare, &_ConnectionHash);
|
||||||
|
fEndpointHash = hash_init(kEndpointHashBuckets,
|
||||||
|
offsetof(TCPConnection, fEndpointHashNext),
|
||||||
|
&_EndpointCompare, &_EndpointHash);
|
||||||
|
|
||||||
|
recursive_lock_init(&fLock, "endpoint manager");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
EndpointManager::~EndpointManager()
|
||||||
|
{
|
||||||
|
hash_uninit(fConnectionHash);
|
||||||
|
hash_uninit(fEndpointHash);
|
||||||
|
|
||||||
|
recursive_lock_destroy(&fLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
EndpointManager::InitCheck() const
|
||||||
|
{
|
||||||
|
if (fConnectionHash == NULL
|
||||||
|
|| fEndpointHash == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
if (fLock.sem < B_OK)
|
||||||
|
return fLock.sem;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - connections
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the endpoint matching the connection.
|
||||||
|
You must hold the manager's lock when calling this method.
|
||||||
|
*/
|
||||||
|
TCPConnection *
|
||||||
|
EndpointManager::_LookupConnection(sockaddr *local, sockaddr *peer)
|
||||||
|
{
|
||||||
|
connection_key key;
|
||||||
|
key.local = local;
|
||||||
|
key.peer = peer;
|
||||||
|
|
||||||
|
return (TCPConnection *)hash_lookup(fConnectionHash, &key);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
EndpointManager::_RemoveConnection(TCPConnection *endpoint)
|
||||||
|
{
|
||||||
|
RecursiveLocker locker(&fLock);
|
||||||
|
return hash_remove(fConnectionHash, endpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
EndpointManager::_DumpConnections()
|
||||||
|
{
|
||||||
|
RecursiveLocker lock(&fLock);
|
||||||
|
|
||||||
|
if (gDomain == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
struct hash_iterator iterator;
|
||||||
|
hash_open(fConnectionHash, &iterator);
|
||||||
|
|
||||||
|
TRACE(("Active TCP Connections:\n"));
|
||||||
|
|
||||||
|
TCPConnection *endpoint;
|
||||||
|
while ((endpoint = (TCPConnection *)hash_next(fConnectionHash, &iterator)) != NULL) {
|
||||||
|
TRACE((" TCPConnection %p: local %s, peer %s\n", endpoint,
|
||||||
|
AddressString(gDomain, (sockaddr *)&endpoint->socket->address, true).Data(),
|
||||||
|
AddressString(gDomain, (sockaddr *)&endpoint->socket->peer, true).Data()));
|
||||||
|
}
|
||||||
|
|
||||||
|
hash_close(fConnectionHash, &iterator, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
EndpointManager::SetConnection(TCPConnection *endpoint,
|
||||||
|
const sockaddr *local, const sockaddr *peer, const sockaddr *interfaceLocal)
|
||||||
|
{
|
||||||
|
RecursiveLocker locker(&fLock);
|
||||||
|
sockaddr localBuffer;
|
||||||
|
|
||||||
|
// need to associate this connection with a real address, not INADDR_ANY
|
||||||
|
if (gAddressModule->is_empty_address(local, false)) {
|
||||||
|
gAddressModule->set_to(&localBuffer, interfaceLocal);
|
||||||
|
gAddressModule->set_port(&localBuffer, gAddressModule->get_port(local));
|
||||||
|
local = &localBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
connection_key key;
|
||||||
|
key.local = local;
|
||||||
|
key.peer = peer;
|
||||||
|
|
||||||
|
if (hash_lookup(fConnectionHash, &key) != NULL)
|
||||||
|
return EADDRINUSE;
|
||||||
|
|
||||||
|
_RemoveConnection(endpoint);
|
||||||
|
|
||||||
|
gAddressModule->set_to((sockaddr *)&endpoint->socket->address, local);
|
||||||
|
gAddressModule->set_to((sockaddr *)&endpoint->socket->peer, peer);
|
||||||
|
|
||||||
|
return hash_insert(fConnectionHash, endpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TCPConnection *
|
||||||
|
EndpointManager::FindConnection(sockaddr *local, sockaddr *peer)
|
||||||
|
{
|
||||||
|
TCPConnection *endpoint = _LookupConnection(local, peer);
|
||||||
|
if (endpoint != NULL) {
|
||||||
|
TRACE(("TCP: Received packet corresponds to explicit endpoint %p\n", endpoint));
|
||||||
|
return endpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
// no explicit endpoint exists, check for wildcard endpoints
|
||||||
|
|
||||||
|
sockaddr wildcard;
|
||||||
|
gAddressModule->set_to_empty_address(&wildcard);
|
||||||
|
|
||||||
|
endpoint = _LookupConnection(local, &wildcard);
|
||||||
|
if (endpoint != NULL) {
|
||||||
|
TRACE(("TCP: Received packet corresponds to wildcard endpoint %p\n", endpoint));
|
||||||
|
return endpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
sockaddr localWildcard;
|
||||||
|
gAddressModule->set_to_empty_address(&localWildcard);
|
||||||
|
gAddressModule->set_port(&localWildcard, gAddressModule->get_port(local));
|
||||||
|
|
||||||
|
endpoint = _LookupConnection(&localWildcard, &wildcard);
|
||||||
|
if (endpoint != NULL) {
|
||||||
|
TRACE(("TCP: Received packet corresponds to local wildcard endpoint %p\n", endpoint));
|
||||||
|
return endpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
// no matching endpoint exists
|
||||||
|
TRACE(("TCP: no matching endpoint!\n"));
|
||||||
|
_DumpConnections();
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - endpoints
|
||||||
|
|
||||||
|
|
||||||
|
TCPConnection *
|
||||||
|
EndpointManager::_LookupEndpoint(uint16 port)
|
||||||
|
{
|
||||||
|
endpoint_key key;
|
||||||
|
key.port = port;
|
||||||
|
|
||||||
|
return (TCPConnection *)hash_lookup(fEndpointHash, &key);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
EndpointManager::Bind(TCPConnection *endpoint, sockaddr *address)
|
||||||
|
{
|
||||||
|
if (gAddressModule->is_empty_address(address, true))
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
uint16 port = gAddressModule->get_port(address);
|
||||||
|
|
||||||
|
// TODO: check the root group instead?
|
||||||
|
if (ntohs(port) <= kLastReservedPort && geteuid() != 0)
|
||||||
|
return B_PERMISSION_DENIED;
|
||||||
|
|
||||||
|
RecursiveLocker locker(&fLock);
|
||||||
|
|
||||||
|
TCPConnection *first = _LookupEndpoint(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;
|
||||||
|
|
||||||
|
if (first != NULL) {
|
||||||
|
TCPConnection *last = first;
|
||||||
|
while (true) {
|
||||||
|
// check if this endpoint binds to a wildcard address
|
||||||
|
if (gAddressModule->is_empty_address((sockaddr *)&last->socket->address, false)) {
|
||||||
|
// you cannot specialize a wildcard endpoint - you have to open the
|
||||||
|
// wildcard endpoint last
|
||||||
|
return B_PERMISSION_DENIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (last->fEndpointNextWithSamePort == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
last = last->fEndpointNextWithSamePort;
|
||||||
|
}
|
||||||
|
|
||||||
|
// "first" stays the first item in the list
|
||||||
|
last->fEndpointNextWithSamePort = endpoint;
|
||||||
|
} else
|
||||||
|
hash_insert(fEndpointHash, endpoint);
|
||||||
|
|
||||||
|
endpoint->fEndpointNextWithSamePort = NULL;
|
||||||
|
hash_insert(fConnectionHash, endpoint);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
EndpointManager::BindToEphemeral(TCPConnection *endpoint, sockaddr *address)
|
||||||
|
{
|
||||||
|
RecursiveLocker locker(&fLock);
|
||||||
|
|
||||||
|
uint32 max = kFirstEphemeralPort + 65536;
|
||||||
|
|
||||||
|
for (int32 i = 1; i < 5; i++) {
|
||||||
|
// try to retrieve a more or less random port
|
||||||
|
uint32 counter = kFirstEphemeralPort;
|
||||||
|
uint32 step = i == 4 ? 1 : system_time() & 0x1f;
|
||||||
|
|
||||||
|
while (counter < max) {
|
||||||
|
uint16 port = counter & 0xffff;
|
||||||
|
if (port <= kLastReservedPort)
|
||||||
|
port += kLastReservedPort;
|
||||||
|
|
||||||
|
port = htons(port);
|
||||||
|
|
||||||
|
TCPConnection *other = _LookupEndpoint(port);
|
||||||
|
if (other == NULL) {
|
||||||
|
// found a port
|
||||||
|
gAddressModule->set_port((sockaddr *)&endpoint->socket->address, port);
|
||||||
|
hash_insert(fEndpointHash, endpoint);
|
||||||
|
hash_insert(fConnectionHash, endpoint);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
counter += step;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// could not find a port!
|
||||||
|
return EADDRINUSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
EndpointManager::Unbind(TCPConnection *endpoint)
|
||||||
|
{
|
||||||
|
if (endpoint == NULL || !endpoint->IsBound())
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
RecursiveLocker locker(&fLock);
|
||||||
|
|
||||||
|
if (!endpoint->IsBound())
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
TCPConnection *other = _LookupEndpoint(gAddressModule->get_port((sockaddr *)&endpoint->socket->address));
|
||||||
|
if (other != endpoint) {
|
||||||
|
// remove endpoint from the list of endpoints with the same port
|
||||||
|
while (other->fEndpointNextWithSamePort != endpoint) {
|
||||||
|
other = other->fEndpointNextWithSamePort;
|
||||||
|
}
|
||||||
|
|
||||||
|
other->fEndpointNextWithSamePort = endpoint->fEndpointNextWithSamePort;
|
||||||
|
} else {
|
||||||
|
// we need to replace the first endpoint in the list
|
||||||
|
hash_remove(fEndpointHash, endpoint);
|
||||||
|
|
||||||
|
other = endpoint->fEndpointNextWithSamePort;
|
||||||
|
if (other != NULL)
|
||||||
|
hash_insert(fEndpointHash, other);
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoint->fEndpointNextWithSamePort = NULL;
|
||||||
|
_RemoveConnection(endpoint);
|
||||||
|
|
||||||
|
endpoint->socket->address.ss_len = 0;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - hash functions
|
||||||
|
|
||||||
|
|
||||||
|
/*static*/ int
|
||||||
|
EndpointManager::_ConnectionCompare(void *_endpoint, const void *_key)
|
||||||
|
{
|
||||||
|
const connection_key *key = (connection_key *)_key;
|
||||||
|
TCPConnection *endpoint = (TCPConnection *)_endpoint;
|
||||||
|
|
||||||
|
if (gAddressModule->equal_addresses_and_ports(key->local,
|
||||||
|
(sockaddr *)&endpoint->socket->address)
|
||||||
|
&& gAddressModule->equal_addresses_and_ports(key->peer,
|
||||||
|
(sockaddr *)&endpoint->socket->peer))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*static*/ uint32
|
||||||
|
EndpointManager::_ConnectionHash(void *_endpoint, const void *_key, uint32 range)
|
||||||
|
{
|
||||||
|
const sockaddr *local;
|
||||||
|
const sockaddr *peer;
|
||||||
|
|
||||||
|
if (_endpoint != NULL) {
|
||||||
|
TCPConnection *endpoint = (TCPConnection *)_endpoint;
|
||||||
|
local = (sockaddr *)&endpoint->socket->address;
|
||||||
|
peer = (sockaddr *)&endpoint->socket->peer;
|
||||||
|
} else {
|
||||||
|
const connection_key *key = (connection_key *)_key;
|
||||||
|
local = key->local;
|
||||||
|
peer = key->peer;
|
||||||
|
}
|
||||||
|
|
||||||
|
return gAddressModule->hash_address_pair(local, peer) % range;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*static*/ int
|
||||||
|
EndpointManager::_EndpointCompare(void *_endpoint, const void *_key)
|
||||||
|
{
|
||||||
|
const endpoint_key *key = (endpoint_key *)_key;
|
||||||
|
TCPConnection *endpoint = (TCPConnection *)_endpoint;
|
||||||
|
|
||||||
|
return gAddressModule->get_port((sockaddr *)&endpoint->socket->address)
|
||||||
|
== key->port ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*static*/ uint32
|
||||||
|
EndpointManager::_EndpointHash(void *_endpoint, const void *_key, uint32 range)
|
||||||
|
{
|
||||||
|
if (_endpoint != NULL) {
|
||||||
|
TCPConnection *endpoint = (TCPConnection *)_endpoint;
|
||||||
|
return gAddressModule->get_port((sockaddr *)&endpoint->socket->address) % range;
|
||||||
|
}
|
||||||
|
|
||||||
|
const endpoint_key *key = (endpoint_key *)_key;
|
||||||
|
return key->port % range;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2006, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Axel Dörfler, [email protected]
|
||||||
|
*/
|
||||||
|
#ifndef ENDPOINT_MANAGER_H
|
||||||
|
#define ENDPOINT_MANAGER_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <lock.h>
|
||||||
|
#include <util/khash.h>
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
|
||||||
|
class TCPConnection;
|
||||||
|
|
||||||
|
class EndpointManager {
|
||||||
|
public:
|
||||||
|
EndpointManager();
|
||||||
|
~EndpointManager();
|
||||||
|
|
||||||
|
status_t InitCheck() const;
|
||||||
|
|
||||||
|
recursive_lock *Locker() { return &fLock; }
|
||||||
|
|
||||||
|
status_t SetConnection(TCPConnection *endpoint, const sockaddr *local,
|
||||||
|
const sockaddr *peer, const sockaddr *interfaceLocal);
|
||||||
|
TCPConnection *FindConnection(sockaddr *local, sockaddr *peer);
|
||||||
|
|
||||||
|
status_t Bind(TCPConnection *endpoint, sockaddr *address);
|
||||||
|
status_t BindToEphemeral(TCPConnection *endpoint, sockaddr *address);
|
||||||
|
status_t Unbind(TCPConnection *endpoint);
|
||||||
|
|
||||||
|
private:
|
||||||
|
TCPConnection *_LookupConnection(sockaddr *local, sockaddr *peer);
|
||||||
|
status_t _RemoveConnection(TCPConnection *endpoint);
|
||||||
|
TCPConnection *_LookupEndpoint(uint16 port);
|
||||||
|
void _DumpConnections();
|
||||||
|
|
||||||
|
static int _ConnectionCompare(void *_endpoint, const void *_key);
|
||||||
|
static uint32 _ConnectionHash(void *_endpoint, const void *_key, uint32 range);
|
||||||
|
static int _EndpointCompare(void *_endpoint, const void *_key);
|
||||||
|
static uint32 _EndpointHash(void *_endpoint, const void *_key, uint32 range);
|
||||||
|
|
||||||
|
hash_table *fConnectionHash;
|
||||||
|
hash_table *fEndpointHash;
|
||||||
|
recursive_lock fLock;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ENDPOINT_MANAGER_H
|
||||||
@@ -16,6 +16,7 @@ KernelAddon tcp :
|
|||||||
tcp.cpp
|
tcp.cpp
|
||||||
TCPConnection.cpp
|
TCPConnection.cpp
|
||||||
BufferQueue.cpp
|
BufferQueue.cpp
|
||||||
|
EndpointManager.cpp
|
||||||
;
|
;
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
|
|||||||
@@ -9,12 +9,19 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "TCPConnection.h"
|
#include "TCPConnection.h"
|
||||||
|
#include "EndpointManager.h"
|
||||||
|
|
||||||
#include <net_buffer.h>
|
#include <net_buffer.h>
|
||||||
#include <net_datalink.h>
|
#include <net_datalink.h>
|
||||||
|
#include <NetBufferUtilities.h>
|
||||||
|
#include <NetUtilities.h>
|
||||||
|
|
||||||
|
#include <lock.h>
|
||||||
|
#include <util/AutoLock.h>
|
||||||
|
#include <util/khash.h>
|
||||||
|
#include <util/list.h>
|
||||||
|
|
||||||
#include <KernelExport.h>
|
#include <KernelExport.h>
|
||||||
#include <util/list.h>
|
|
||||||
|
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <netinet/ip.h>
|
#include <netinet/ip.h>
|
||||||
@@ -23,13 +30,6 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <lock.h>
|
|
||||||
#include <util/AutoLock.h>
|
|
||||||
#include <util/khash.h>
|
|
||||||
|
|
||||||
#include <NetBufferUtilities.h>
|
|
||||||
#include <NetUtilities.h>
|
|
||||||
|
|
||||||
|
|
||||||
// Things this implementation currently doesn't implement:
|
// Things this implementation currently doesn't implement:
|
||||||
// TCP, RFC 793
|
// TCP, RFC 793
|
||||||
@@ -197,7 +197,7 @@ TCPConnection::Connect(const struct sockaddr *address)
|
|||||||
if (address->sa_family != AF_INET)
|
if (address->sa_family != AF_INET)
|
||||||
return EAFNOSUPPORT;
|
return EAFNOSUPPORT;
|
||||||
|
|
||||||
//BenaphoreLocker lock(&fSendLock);
|
RecursiveLocker locker(&fLock);
|
||||||
|
|
||||||
TRACE((" TCP: Connect(): in state %d\n", fState));
|
TRACE((" TCP: Connect(): in state %d\n", fState));
|
||||||
|
|
||||||
@@ -218,24 +218,9 @@ TCPConnection::Connect(const struct sockaddr *address)
|
|||||||
return ENETUNREACH;
|
return ENETUNREACH;
|
||||||
}
|
}
|
||||||
|
|
||||||
remove_connection(this);
|
|
||||||
// we need to temporarily remove us from the connection list, as we're
|
|
||||||
// changing our addresses
|
|
||||||
|
|
||||||
// need to associate this connection with a real address, not INADDR_ANY
|
|
||||||
if (gAddressModule->is_empty_address((sockaddr *)&socket->address, false)) {
|
|
||||||
TRACE((" TCP: Connect(): Local Address is INADDR_ANY\n"));
|
|
||||||
uint16 port = gAddressModule->get_port((sockaddr *)&socket->address);
|
|
||||||
gAddressModule->set_to((sockaddr *)&socket->address,
|
|
||||||
(sockaddr *)fRoute->interface->address);
|
|
||||||
gAddressModule->set_port((sockaddr *)&socket->address, port);
|
|
||||||
// need to reset the port after overwriting the address
|
|
||||||
}
|
|
||||||
|
|
||||||
gAddressModule->set_to((sockaddr *)&socket->peer, address);
|
|
||||||
|
|
||||||
// make sure connection does not already exist
|
// make sure connection does not already exist
|
||||||
status_t status = insert_connection(this);
|
status_t status = gEndpointManager->SetConnection(this,
|
||||||
|
(sockaddr *)&socket->address, address, fRoute->interface->address);
|
||||||
if (status < B_OK) {
|
if (status < B_OK) {
|
||||||
TRACE((" TCP: Connect(): could not add connection: %s!\n", strerror(status)));
|
TRACE((" TCP: Connect(): could not add connection: %s!\n", strerror(status)));
|
||||||
return status;
|
return status;
|
||||||
@@ -251,7 +236,6 @@ TCPConnection::Connect(const struct sockaddr *address)
|
|||||||
&& (0xffffUL << fReceiveWindowShift) < socket->receive.buffer_size) {
|
&& (0xffffUL << fReceiveWindowShift) < socket->receive.buffer_size) {
|
||||||
fReceiveWindowShift++;
|
fReceiveWindowShift++;
|
||||||
}
|
}
|
||||||
dprintf("************************* size = %ld, shift = %d\n", socket->receive.buffer_size, fReceiveWindowShift);
|
|
||||||
|
|
||||||
TRACE((" TCP: Connect(): starting 3-way handshake...\n"));
|
TRACE((" TCP: Connect(): starting 3-way handshake...\n"));
|
||||||
|
|
||||||
@@ -274,6 +258,8 @@ dprintf("************************* size = %ld, shift = %d\n", socket->receive.bu
|
|||||||
return EINPROGRESS;
|
return EINPROGRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
locker.Unlock();
|
||||||
|
|
||||||
status = acquire_sem_etc(fSendLock, 1, B_RELATIVE_TIMEOUT | B_CAN_INTERRUPT, timeout);
|
status = acquire_sem_etc(fSendLock, 1, B_RELATIVE_TIMEOUT | B_CAN_INTERRUPT, timeout);
|
||||||
|
|
||||||
TRACE((" TCP: Connect(): Connection complete: %s\n", strerror(status)));
|
TRACE((" TCP: Connect(): Connection complete: %s\n", strerror(status)));
|
||||||
@@ -308,11 +294,7 @@ TCPConnection::Bind(sockaddr *address)
|
|||||||
TRACE(("TCP:%p.Bind() on address %s\n", this,
|
TRACE(("TCP:%p.Bind() on address %s\n", this,
|
||||||
AddressString(gDomain, address, true).Data()));
|
AddressString(gDomain, address, true).Data()));
|
||||||
|
|
||||||
if (address->sa_family != AF_INET)
|
RecursiveLocker lock(fLock);
|
||||||
return EAFNOSUPPORT;
|
|
||||||
|
|
||||||
//BenaphoreLocker lock(&fSendLock);
|
|
||||||
// TODO: there is no lock yet for these things...
|
|
||||||
|
|
||||||
if (fState != CLOSED)
|
if (fState != CLOSED)
|
||||||
return EISCONN;
|
return EISCONN;
|
||||||
@@ -322,21 +304,10 @@ TCPConnection::Bind(sockaddr *address)
|
|||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
gAddressModule->set_to((sockaddr *)&socket->address, address);
|
if (gAddressModule->get_port(address) == 0)
|
||||||
|
status = gEndpointManager->BindToEphemeral(this, address);
|
||||||
if (gAddressModule->get_port((sockaddr *)&socket->address) == 0) {
|
else
|
||||||
// assign ephemeral port
|
status = gEndpointManager->Bind(this, address);
|
||||||
// TODO: use port 40000 and following for now
|
|
||||||
static int e = 40000;
|
|
||||||
gAddressModule->set_port((sockaddr *)&socket->address, htons(e++));
|
|
||||||
|
|
||||||
TRACE(("TCP:%p.Bind() on address with ephemeral port %s, peer %s\n", this,
|
|
||||||
AddressString(gDomain, (sockaddr *)&socket->address, true).Data(),
|
|
||||||
AddressString(gDomain, (sockaddr *)&socket->peer, true).Data()));
|
|
||||||
status = insert_connection(this);
|
|
||||||
} else {
|
|
||||||
status = insert_connection(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@@ -345,18 +316,10 @@ TCPConnection::Bind(sockaddr *address)
|
|||||||
status_t
|
status_t
|
||||||
TCPConnection::Unbind(struct sockaddr *address)
|
TCPConnection::Unbind(struct sockaddr *address)
|
||||||
{
|
{
|
||||||
TRACE(("TCP:%p.Unbind()\n", this ));
|
TRACE(("TCP:%p.Unbind()\n", this));
|
||||||
|
|
||||||
//BenaphoreLocker lock(&fSendLock);
|
RecursiveLocker lock(fLock);
|
||||||
// TODO: there is no lock yet for these things...
|
return gEndpointManager->Unbind(this);
|
||||||
|
|
||||||
status_t status = remove_connection(this);
|
|
||||||
if (status != B_OK)
|
|
||||||
return status;
|
|
||||||
|
|
||||||
gAddressModule->set_to_empty_address((sockaddr *)&socket->address);
|
|
||||||
gAddressModule->set_port((sockaddr *)&socket->address, 0);
|
|
||||||
return B_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -364,9 +327,13 @@ status_t
|
|||||||
TCPConnection::Listen(int count)
|
TCPConnection::Listen(int count)
|
||||||
{
|
{
|
||||||
TRACE(("TCP:%p.Listen()\n", this));
|
TRACE(("TCP:%p.Listen()\n", this));
|
||||||
//BenaphoreLocker lock(&fSendLock);
|
|
||||||
|
RecursiveLocker lock(fLock);
|
||||||
|
|
||||||
if (fState != CLOSED)
|
if (fState != CLOSED)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
if (!IsBound())
|
||||||
|
return EDESTADDRREQ;
|
||||||
|
|
||||||
fAcceptSemaphore = create_sem(0, "tcp accept");
|
fAcceptSemaphore = create_sem(0, "tcp accept");
|
||||||
fState = LISTEN;
|
fState = LISTEN;
|
||||||
@@ -504,6 +471,13 @@ TCPConnection::ReadAvailable()
|
|||||||
// #pragma mark - misc
|
// #pragma mark - misc
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
TCPConnection::IsBound() const
|
||||||
|
{
|
||||||
|
return !gAddressModule->is_empty_address((sockaddr *)&socket->address, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
TCPConnection::DelayedAcknowledge()
|
TCPConnection::DelayedAcknowledge()
|
||||||
{
|
{
|
||||||
@@ -581,7 +555,8 @@ TCPConnection::ListenReceive(tcp_segment_header &segment, net_buffer *buffer)
|
|||||||
if (connection->fRoute == NULL)
|
if (connection->fRoute == NULL)
|
||||||
return DROP;
|
return DROP;
|
||||||
|
|
||||||
if (insert_connection(connection) < B_OK)
|
if (gEndpointManager->SetConnection(connection, (sockaddr *)&buffer->destination,
|
||||||
|
(sockaddr *)&buffer->source, NULL) < B_OK)
|
||||||
return DROP;
|
return DROP;
|
||||||
|
|
||||||
connection->fInitialReceiveSequence = segment.sequence;
|
connection->fInitialReceiveSequence = segment.sequence;
|
||||||
@@ -1041,7 +1016,6 @@ TCPConnection::_SendQueued(bool force)
|
|||||||
uint32 sendWindow = fSendWindow;
|
uint32 sendWindow = fSendWindow;
|
||||||
uint32 available = fSendQueue.Available(fSendNext);
|
uint32 available = fSendQueue.Available(fSendNext);
|
||||||
bool outstandingAcknowledge = fSendMax != fSendUnacknowledged;
|
bool outstandingAcknowledge = fSendMax != fSendUnacknowledged;
|
||||||
dprintf("fSendWindow = %lu, available = %lu, fSendNext = %lu, fSendUnacknowledged = %lu\n", fSendWindow, available, (uint32)fSendNext, (uint32)fSendUnacknowledged);
|
|
||||||
|
|
||||||
if (force && sendWindow == 0 && fSendNext <= fSendQueue.LastSequence()) {
|
if (force && sendWindow == 0 && fSendNext <= fSendQueue.LastSequence()) {
|
||||||
// send one byte of data to ask for a window update
|
// send one byte of data to ask for a window update
|
||||||
@@ -1073,7 +1047,6 @@ dprintf("fSendWindow = %lu, available = %lu, fSendNext = %lu, fSendUnacknowledge
|
|||||||
segment.urgent_offset = 0;
|
segment.urgent_offset = 0;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
dprintf("length = %ld, segmentLength = %lu\n", length, segmentLength);
|
|
||||||
// Determine if we should really send this segment
|
// Determine if we should really send this segment
|
||||||
if (!force && !_ShouldSendSegment(segment, segmentLength, outstandingAcknowledge)) {
|
if (!force && !_ShouldSendSegment(segment, segmentLength, outstandingAcknowledge)) {
|
||||||
if (fSendQueue.Available()
|
if (fSendQueue.Available()
|
||||||
@@ -1127,6 +1100,9 @@ dprintf("length = %ld, segmentLength = %lu\n", length, segmentLength);
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: we need to trim the segment to the max segment size in case
|
||||||
|
// the options made it too large
|
||||||
|
|
||||||
status = next->module->send_routed_data(next, fRoute, buffer);
|
status = next->module->send_routed_data(next, fRoute, buffer);
|
||||||
if (status < B_OK) {
|
if (status < B_OK) {
|
||||||
gBufferModule->free(buffer);
|
gBufferModule->free(buffer);
|
||||||
@@ -1205,35 +1181,3 @@ TCPConnection::_TimeWait(struct net_timer *timer, void *data)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - hash functions
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
TCPConnection::Compare(void *_connection, const void *_key)
|
|
||||||
{
|
|
||||||
const tcp_connection_key *key = (tcp_connection_key *)_key;
|
|
||||||
TCPConnection *connection = ((TCPConnection *)_connection);
|
|
||||||
|
|
||||||
if (gAddressModule->equal_addresses_and_ports(key->local,
|
|
||||||
(sockaddr *)&connection->socket->address)
|
|
||||||
&& gAddressModule->equal_addresses_and_ports(key->peer,
|
|
||||||
(sockaddr *)&connection->socket->peer))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
uint32
|
|
||||||
TCPConnection::Hash(void *_connection, const void *_key, uint32 range)
|
|
||||||
{
|
|
||||||
if (_connection != NULL) {
|
|
||||||
TCPConnection *connection = (TCPConnection *)_connection;
|
|
||||||
return gAddressModule->hash_address_pair((sockaddr *)&connection->socket->address,
|
|
||||||
(sockaddr *)&connection->socket->peer) % range;
|
|
||||||
}
|
|
||||||
|
|
||||||
const tcp_connection_key *key = (tcp_connection_key *)_key;
|
|
||||||
return gAddressModule->hash_address_pair(key->local, key->peer) % range;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -20,6 +20,8 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
|
||||||
|
class EndpointManager;
|
||||||
|
|
||||||
class TCPConnection : public net_protocol {
|
class TCPConnection : public net_protocol {
|
||||||
public:
|
public:
|
||||||
TCPConnection(net_socket *socket);
|
TCPConnection(net_socket *socket);
|
||||||
@@ -44,6 +46,7 @@ class TCPConnection : public net_protocol {
|
|||||||
size_t ReadAvailable();
|
size_t ReadAvailable();
|
||||||
|
|
||||||
tcp_state State() const { return fState; }
|
tcp_state State() const { return fState; }
|
||||||
|
bool IsBound() const;
|
||||||
|
|
||||||
status_t DelayedAcknowledge();
|
status_t DelayedAcknowledge();
|
||||||
status_t SendAcknowledge();
|
status_t SendAcknowledge();
|
||||||
@@ -53,11 +56,9 @@ class TCPConnection : public net_protocol {
|
|||||||
net_buffer *buffer);
|
net_buffer *buffer);
|
||||||
int32 Receive(tcp_segment_header& segment, net_buffer *buffer);
|
int32 Receive(tcp_segment_header& segment, net_buffer *buffer);
|
||||||
|
|
||||||
static int Compare(void *_packet, const void *_key);
|
|
||||||
static uint32 Hash(void *_packet, const void *_key, uint32 range);
|
|
||||||
static int32 HashOffset() { return offsetof(TCPConnection, fHashNext); }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
friend class EndpointManager;
|
||||||
|
|
||||||
void _StartPersistTimer();
|
void _StartPersistTimer();
|
||||||
uint8 _CurrentFlags();
|
uint8 _CurrentFlags();
|
||||||
bool _ShouldSendSegment(tcp_segment_header &segment, uint32 length,
|
bool _ShouldSendSegment(tcp_segment_header &segment, uint32 length,
|
||||||
@@ -69,7 +70,9 @@ class TCPConnection : public net_protocol {
|
|||||||
static void _PersistTimer(net_timer *timer, void *data);
|
static void _PersistTimer(net_timer *timer, void *data);
|
||||||
static void _DelayedAcknowledgeTimer(net_timer *timer, void *data);
|
static void _DelayedAcknowledgeTimer(net_timer *timer, void *data);
|
||||||
|
|
||||||
TCPConnection *fHashNext;
|
TCPConnection *fConnectionHashNext;
|
||||||
|
TCPConnection *fEndpointHashNext;
|
||||||
|
TCPConnection *fEndpointNextWithSamePort;
|
||||||
|
|
||||||
recursive_lock fLock;
|
recursive_lock fLock;
|
||||||
sem_id fReceiveLock;
|
sem_id fReceiveLock;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "EndpointManager.h"
|
||||||
#include "TCPConnection.h"
|
#include "TCPConnection.h"
|
||||||
|
|
||||||
#include <net_protocol.h>
|
#include <net_protocol.h>
|
||||||
@@ -37,45 +38,13 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define MAX_HASH_TCP 64
|
|
||||||
|
|
||||||
|
|
||||||
net_domain *gDomain;
|
net_domain *gDomain;
|
||||||
net_address_module_info *gAddressModule;
|
net_address_module_info *gAddressModule;
|
||||||
net_buffer_module_info *gBufferModule;
|
net_buffer_module_info *gBufferModule;
|
||||||
net_datalink_module_info *gDatalinkModule;
|
net_datalink_module_info *gDatalinkModule;
|
||||||
net_socket_module_info *gSocketModule;
|
net_socket_module_info *gSocketModule;
|
||||||
net_stack_module_info *gStackModule;
|
net_stack_module_info *gStackModule;
|
||||||
hash_table *gConnectionHash;
|
EndpointManager *gEndpointManager;
|
||||||
recursive_lock gConnectionLock;
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef TRACE_TCP
|
|
||||||
# define DUMP_TCP_HASH tcp_dump_hash()
|
|
||||||
// Dumps the TCP Connection hash. gConnectionLock must NOT be held when calling
|
|
||||||
void
|
|
||||||
tcp_dump_hash()
|
|
||||||
{
|
|
||||||
RecursiveLocker lock(&gConnectionLock);
|
|
||||||
if (gDomain == NULL) {
|
|
||||||
TRACE(("Unable to dump TCP Connections!\n"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
struct hash_iterator iterator;
|
|
||||||
hash_open(gConnectionHash, &iterator);
|
|
||||||
TCPConnection *connection;
|
|
||||||
hash_rewind(gConnectionHash, &iterator);
|
|
||||||
TRACE(("Active TCP Connections:\n"));
|
|
||||||
while ((connection = (TCPConnection *)hash_next(gConnectionHash, &iterator)) != NULL) {
|
|
||||||
TRACE((" TCPConnection %p: local %s, peer %s\n", connection,
|
|
||||||
AddressString(gDomain, (sockaddr *)&connection->socket->address, true).Data(),
|
|
||||||
AddressString(gDomain, (sockaddr *)&connection->socket->peer, true).Data()));
|
|
||||||
}
|
|
||||||
hash_close(gConnectionHash, &iterator, false);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
# define DUMP_TCP_HASH ;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
@@ -290,76 +259,6 @@ reply_with_reset(tcp_segment_header &segment, net_buffer *buffer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TCPConnection *
|
|
||||||
lookup_connection(sockaddr *local, sockaddr *peer)
|
|
||||||
{
|
|
||||||
tcp_connection_key key;
|
|
||||||
key.local = local;
|
|
||||||
key.peer = peer;
|
|
||||||
|
|
||||||
return (TCPConnection *)hash_lookup(gConnectionHash, &key);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
status_t
|
|
||||||
remove_connection(TCPConnection *connection)
|
|
||||||
{
|
|
||||||
RecursiveLocker hashLock(&gConnectionLock);
|
|
||||||
return hash_remove(gConnectionHash, connection);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
status_t
|
|
||||||
insert_connection(TCPConnection *connection)
|
|
||||||
{
|
|
||||||
RecursiveLocker hashLock(&gConnectionLock);
|
|
||||||
|
|
||||||
tcp_connection_key key;
|
|
||||||
key.local = (sockaddr *)&connection->socket->address;
|
|
||||||
key.peer = (sockaddr *)&connection->socket->peer;
|
|
||||||
|
|
||||||
if (hash_lookup(gConnectionHash, &key) != NULL)
|
|
||||||
return EADDRINUSE;
|
|
||||||
|
|
||||||
return hash_insert(gConnectionHash, connection);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
TCPConnection *
|
|
||||||
find_connection(sockaddr *local, sockaddr *peer)
|
|
||||||
{
|
|
||||||
TCPConnection *connection = lookup_connection(local, peer);
|
|
||||||
if (connection != NULL) {
|
|
||||||
TRACE(("TCP: Received packet corresponds to explicit connection %p\n", connection));
|
|
||||||
return connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
// no explicit connection exists, check for wildcard connections
|
|
||||||
|
|
||||||
sockaddr wildcard;
|
|
||||||
gAddressModule->set_to_empty_address(&wildcard);
|
|
||||||
|
|
||||||
connection = lookup_connection(local, &wildcard);
|
|
||||||
if (connection != NULL) {
|
|
||||||
TRACE(("TCP: Received packet corresponds to wildcard connection %p\n", connection));
|
|
||||||
return connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
sockaddr localWildcard;
|
|
||||||
gAddressModule->set_to_empty_address(&localWildcard);
|
|
||||||
gAddressModule->set_port(&localWildcard, gAddressModule->get_port(local));
|
|
||||||
|
|
||||||
connection = lookup_connection(&localWildcard, &wildcard);
|
|
||||||
if (connection != NULL) {
|
|
||||||
TRACE(("TCP: Received packet corresponds to local wildcard connection %p\n", connection));
|
|
||||||
return connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
// no matching connection exists
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - protocol API
|
// #pragma mark - protocol API
|
||||||
|
|
||||||
|
|
||||||
@@ -417,7 +316,6 @@ tcp_free(net_protocol *protocol)
|
|||||||
status_t
|
status_t
|
||||||
tcp_connect(net_protocol *protocol, const struct sockaddr *address)
|
tcp_connect(net_protocol *protocol, const struct sockaddr *address)
|
||||||
{
|
{
|
||||||
DUMP_TCP_HASH;
|
|
||||||
return ((TCPConnection *)protocol)->Connect(address);
|
return ((TCPConnection *)protocol)->Connect(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -569,11 +467,11 @@ tcp_receive_data(net_buffer *buffer)
|
|||||||
bufferHeader.Remove(headerLength);
|
bufferHeader.Remove(headerLength);
|
||||||
// we no longer need to keep the header around
|
// we no longer need to keep the header around
|
||||||
|
|
||||||
RecursiveLocker hashLock(&gConnectionLock);
|
RecursiveLocker locker(gEndpointManager->Locker());
|
||||||
int32 segmentAction = DROP;
|
int32 segmentAction = DROP;
|
||||||
|
|
||||||
TCPConnection *connection = find_connection((struct sockaddr *)&buffer->destination,
|
TCPConnection *connection = gEndpointManager->FindConnection(
|
||||||
(struct sockaddr *)&buffer->source);
|
(struct sockaddr *)&buffer->destination, (struct sockaddr *)&buffer->source);
|
||||||
if (connection != NULL) {
|
if (connection != NULL) {
|
||||||
RecursiveLocker locker(connection->Lock());
|
RecursiveLocker locker(connection->Lock());
|
||||||
|
|
||||||
@@ -661,12 +559,12 @@ tcp_init()
|
|||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
goto err3;
|
goto err3;
|
||||||
|
|
||||||
gConnectionHash = hash_init(MAX_HASH_TCP, TCPConnection::HashOffset(),
|
gEndpointManager = new (std::nothrow) EndpointManager();
|
||||||
&TCPConnection::Compare, &TCPConnection::Hash);
|
if (gEndpointManager == NULL) {
|
||||||
if (gConnectionHash == NULL)
|
status = B_NO_MEMORY;
|
||||||
goto err4;
|
goto err4;
|
||||||
|
}
|
||||||
status = recursive_lock_init(&gConnectionLock, "tcp connection hash");
|
status = gEndpointManager->InitCheck();
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
goto err5;
|
goto err5;
|
||||||
|
|
||||||
@@ -675,26 +573,24 @@ tcp_init()
|
|||||||
"network/protocols/ipv4/v1",
|
"network/protocols/ipv4/v1",
|
||||||
NULL);
|
NULL);
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
goto err6;
|
goto err5;
|
||||||
|
|
||||||
status = gStackModule->register_domain_protocols(AF_INET, SOCK_STREAM, IPPROTO_TCP,
|
status = gStackModule->register_domain_protocols(AF_INET, SOCK_STREAM, IPPROTO_TCP,
|
||||||
"network/protocols/tcp/v1",
|
"network/protocols/tcp/v1",
|
||||||
"network/protocols/ipv4/v1",
|
"network/protocols/ipv4/v1",
|
||||||
NULL);
|
NULL);
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
goto err6;
|
goto err5;
|
||||||
|
|
||||||
status = gStackModule->register_domain_receiving_protocol(AF_INET, IPPROTO_TCP,
|
status = gStackModule->register_domain_receiving_protocol(AF_INET, IPPROTO_TCP,
|
||||||
"network/protocols/tcp/v1");
|
"network/protocols/tcp/v1");
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
goto err6;
|
goto err5;
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
err6:
|
|
||||||
recursive_lock_destroy(&gConnectionLock);
|
|
||||||
err5:
|
err5:
|
||||||
hash_uninit(gConnectionHash);
|
delete gEndpointManager;
|
||||||
err4:
|
err4:
|
||||||
put_module(NET_DATALINK_MODULE_NAME);
|
put_module(NET_DATALINK_MODULE_NAME);
|
||||||
err3:
|
err3:
|
||||||
@@ -712,8 +608,8 @@ err1:
|
|||||||
static status_t
|
static status_t
|
||||||
tcp_uninit()
|
tcp_uninit()
|
||||||
{
|
{
|
||||||
recursive_lock_destroy(&gConnectionLock);
|
delete gEndpointManager;
|
||||||
hash_uninit(gConnectionHash);
|
|
||||||
put_module(NET_DATALINK_MODULE_NAME);
|
put_module(NET_DATALINK_MODULE_NAME);
|
||||||
put_module(NET_SOCKET_MODULE_NAME);
|
put_module(NET_SOCKET_MODULE_NAME);
|
||||||
put_module(NET_BUFFER_MODULE_NAME);
|
put_module(NET_BUFFER_MODULE_NAME);
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
|
||||||
class TCPConnection;
|
class EndpointManager;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
// establishing a connection
|
// establishing a connection
|
||||||
@@ -154,11 +154,6 @@ enum tcp_segment_action {
|
|||||||
IMMEDIATE_ACKNOWLEDGE = 0x08,
|
IMMEDIATE_ACKNOWLEDGE = 0x08,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tcp_connection_key {
|
|
||||||
const sockaddr *local;
|
|
||||||
const sockaddr *peer;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
extern net_domain *gDomain;
|
extern net_domain *gDomain;
|
||||||
extern net_address_module_info *gAddressModule;
|
extern net_address_module_info *gAddressModule;
|
||||||
@@ -166,12 +161,9 @@ extern net_buffer_module_info *gBufferModule;
|
|||||||
extern net_datalink_module_info *gDatalinkModule;
|
extern net_datalink_module_info *gDatalinkModule;
|
||||||
extern net_socket_module_info *gSocketModule;
|
extern net_socket_module_info *gSocketModule;
|
||||||
extern net_stack_module_info *gStackModule;
|
extern net_stack_module_info *gStackModule;
|
||||||
//extern hash_table *gConnectionHash;
|
extern EndpointManager *gEndpointManager;
|
||||||
//extern benaphore gConnectionLock;
|
|
||||||
|
|
||||||
|
|
||||||
status_t add_tcp_header(tcp_segment_header &segment, net_buffer *buffer);
|
status_t add_tcp_header(tcp_segment_header &segment, net_buffer *buffer);
|
||||||
status_t remove_connection(TCPConnection *connection);
|
|
||||||
status_t insert_connection(TCPConnection *connection);
|
|
||||||
|
|
||||||
#endif // TCP_H
|
#endif // TCP_H
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ SimpleTest tcp_tester :
|
|||||||
tcp.cpp
|
tcp.cpp
|
||||||
TCPConnection.cpp
|
TCPConnection.cpp
|
||||||
BufferQueue.cpp
|
BufferQueue.cpp
|
||||||
|
EndpointManager.cpp
|
||||||
|
|
||||||
# misc
|
# misc
|
||||||
argv.c
|
argv.c
|
||||||
@@ -45,7 +46,7 @@ SimpleTest tcp_tester :
|
|||||||
;
|
;
|
||||||
|
|
||||||
SEARCH on [ FGristFiles
|
SEARCH on [ FGristFiles
|
||||||
tcp.cpp TCPConnection.cpp BufferQueue.cpp
|
tcp.cpp TCPConnection.cpp BufferQueue.cpp EndpointManager.cpp
|
||||||
] = [ FDirName $(HAIKU_TOP) src add-ons kernel network protocols tcp ] ;
|
] = [ FDirName $(HAIKU_TOP) src add-ons kernel network protocols tcp ] ;
|
||||||
|
|
||||||
SEARCH on [ FGristFiles
|
SEARCH on [ FGristFiles
|
||||||
|
|||||||
Reference in New Issue
Block a user