made TCP handle multiple domains.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20718 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Hugo Santos
2007-04-16 00:27:39 +00:00
parent d5b5a2c2f8
commit 03d7f17e07
6 changed files with 218 additions and 150 deletions
@@ -26,6 +26,7 @@
struct connection_key {
net_address_module_info *address_module;
const sockaddr *local;
const sockaddr *peer;
};
@@ -42,7 +43,8 @@ static const uint16 kLastReservedPort = 1023;
static const uint16 kFirstEphemeralPort = 40000;
EndpointManager::EndpointManager()
EndpointManager::EndpointManager(net_domain *domain)
: fDomain(domain)
{
fConnectionHash = hash_init(kConnectionHashBuckets,
offsetof(TCPEndpoint, fConnectionHashNext),
@@ -89,6 +91,7 @@ TCPEndpoint *
EndpointManager::_LookupConnection(sockaddr *local, sockaddr *peer)
{
connection_key key;
key.address_module = AddressModule();
key.local = local;
key.peer = peer;
@@ -109,9 +112,6 @@ EndpointManager::_DumpConnections()
{
RecursiveLocker lock(&fLock);
if (gDomain == NULL)
return;
struct hash_iterator iterator;
hash_open(fConnectionHash, &iterator);
@@ -120,8 +120,8 @@ EndpointManager::_DumpConnections()
TCPEndpoint *endpoint;
while ((endpoint = (TCPEndpoint *)hash_next(fConnectionHash, &iterator)) != NULL) {
TRACE((" TCPEndpoint %p: local %s, peer %s\n", endpoint,
AddressString(gDomain, (sockaddr *)&endpoint->socket->address, true).Data(),
AddressString(gDomain, (sockaddr *)&endpoint->socket->peer, true).Data()));
AddressString(Domain(), (sockaddr *)&endpoint->socket->address, true).Data(),
AddressString(Domain(), (sockaddr *)&endpoint->socket->peer, true).Data()));
}
hash_close(fConnectionHash, &iterator, false);
@@ -138,13 +138,14 @@ EndpointManager::SetConnection(TCPEndpoint *endpoint,
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));
if (AddressModule()->is_empty_address(local, false)) {
AddressModule()->set_to(&localBuffer, interfaceLocal);
AddressModule()->set_port(&localBuffer, AddressModule()->get_port(local));
local = &localBuffer;
}
connection_key key;
key.address_module = AddressModule();
key.local = local;
key.peer = peer;
@@ -153,8 +154,8 @@ EndpointManager::SetConnection(TCPEndpoint *endpoint,
_RemoveConnection(endpoint);
gAddressModule->set_to((sockaddr *)&endpoint->socket->address, local);
gAddressModule->set_to((sockaddr *)&endpoint->socket->peer, peer);
AddressModule()->set_to((sockaddr *)&endpoint->socket->address, local);
AddressModule()->set_to((sockaddr *)&endpoint->socket->peer, peer);
return hash_insert(fConnectionHash, endpoint);
}
@@ -172,7 +173,7 @@ EndpointManager::FindConnection(sockaddr *local, sockaddr *peer)
// no explicit endpoint exists, check for wildcard endpoints
sockaddr wildcard;
gAddressModule->set_to_empty_address(&wildcard);
AddressModule()->set_to_empty_address(&wildcard);
endpoint = _LookupConnection(local, &wildcard);
if (endpoint != NULL) {
@@ -181,8 +182,8 @@ EndpointManager::FindConnection(sockaddr *local, sockaddr *peer)
}
sockaddr localWildcard;
gAddressModule->set_to_empty_address(&localWildcard);
gAddressModule->set_port(&localWildcard, gAddressModule->get_port(local));
AddressModule()->set_to_empty_address(&localWildcard);
AddressModule()->set_port(&localWildcard, AddressModule()->get_port(local));
endpoint = _LookupConnection(&localWildcard, &wildcard);
if (endpoint != NULL) {
@@ -217,12 +218,12 @@ EndpointManager::Bind(TCPEndpoint *endpoint)
sockaddr *address = (sockaddr *)&endpoint->socket->address;
TRACE(("EndpointManager::Bind(%p, %s)\n", endpoint,
AddressString(gDomain, address, true).Data()));
AddressString(Domain(), address, true).Data()));
if (gAddressModule->is_empty_address(address, true))
if (AddressModule()->is_empty_address(address, true))
return B_BAD_VALUE;
uint16 port = gAddressModule->get_port(address);
uint16 port = AddressModule()->get_port(address);
// TODO: check the root group instead?
if (ntohs(port) <= kLastReservedPort && geteuid() != 0)
@@ -245,7 +246,7 @@ EndpointManager::Bind(TCPEndpoint *endpoint)
TCPEndpoint *last = first;
while (true) {
// check if this endpoint binds to a wildcard address
if (gAddressModule->is_empty_address((sockaddr *)&last->socket->address, false)) {
if (AddressModule()->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;
@@ -293,9 +294,9 @@ EndpointManager::BindToEphemeral(TCPEndpoint *endpoint)
TCPEndpoint *other = _LookupEndpoint(port);
if (other == NULL) {
// found a port
gAddressModule->set_port((sockaddr *)&endpoint->socket->address, port);
AddressModule()->set_port((sockaddr *)&endpoint->socket->address, port);
TRACE((" EndpointManager::BindToEphemeral(%p) -> %s\n", endpoint,
AddressString(gDomain, (sockaddr *)&endpoint->socket->address, true).Data()));
AddressString(Domain(), (sockaddr *)&endpoint->socket->address, true).Data()));
endpoint->fEndpointNextWithSamePort = NULL;
hash_insert(fEndpointHash, endpoint);
hash_insert(fConnectionHash, endpoint);
@@ -320,7 +321,7 @@ EndpointManager::Unbind(TCPEndpoint *endpoint)
RecursiveLocker locker(&fLock);
if (!endpoint->fSpawned) {
TCPEndpoint *other = _LookupEndpoint(gAddressModule->get_port(
TCPEndpoint *other = _LookupEndpoint(AddressModule()->get_port(
(sockaddr *)&endpoint->socket->address));
if (other != endpoint) {
// remove endpoint from the list of endpoints with the same port
@@ -351,6 +352,45 @@ EndpointManager::Unbind(TCPEndpoint *endpoint)
}
status_t
EndpointManager::ReplyWithReset(tcp_segment_header &segment,
net_buffer *buffer)
{
TRACE(("TCP: Sending RST...\n"));
net_buffer *reply = gBufferModule->create(512);
if (reply == NULL)
return B_NO_MEMORY;
AddressModule()->set_to((sockaddr *)&reply->source,
(sockaddr *)&buffer->destination);
AddressModule()->set_to((sockaddr *)&reply->destination,
(sockaddr *)&buffer->source);
tcp_segment_header outSegment;
outSegment.flags = TCP_FLAG_RESET;
outSegment.sequence = 0;
outSegment.acknowledge = 0;
outSegment.advertised_window = 0;
outSegment.urgent_offset = 0;
if ((segment.flags & TCP_FLAG_ACKNOWLEDGE) == 0) {
outSegment.flags |= TCP_FLAG_ACKNOWLEDGE;
outSegment.acknowledge = segment.sequence + buffer->size;
} else
outSegment.sequence = segment.acknowledge;
status_t status = add_tcp_header(AddressModule(), outSegment, reply);
if (status == B_OK)
status = Domain()->module->send_data(NULL, reply);
if (status != B_OK)
gBufferModule->free(reply);
return status;
}
// #pragma mark - hash functions
@@ -360,9 +400,9 @@ EndpointManager::_ConnectionCompare(void *_endpoint, const void *_key)
const connection_key *key = (connection_key *)_key;
TCPEndpoint *endpoint = (TCPEndpoint *)_endpoint;
if (gAddressModule->equal_addresses_and_ports(key->local,
if (key->address_module->equal_addresses_and_ports(key->local,
(sockaddr *)&endpoint->socket->address)
&& gAddressModule->equal_addresses_and_ports(key->peer,
&& key->address_module->equal_addresses_and_ports(key->peer,
(sockaddr *)&endpoint->socket->peer))
return 0;
@@ -373,20 +413,23 @@ EndpointManager::_ConnectionCompare(void *_endpoint, const void *_key)
/*static*/ uint32
EndpointManager::_ConnectionHash(void *_endpoint, const void *_key, uint32 range)
{
net_address_module_info *address_module;
const sockaddr *local;
const sockaddr *peer;
if (_endpoint != NULL) {
TCPEndpoint *endpoint = (TCPEndpoint *)_endpoint;
address_module = endpoint->AddressModule();
local = (sockaddr *)&endpoint->socket->address;
peer = (sockaddr *)&endpoint->socket->peer;
} else {
const connection_key *key = (connection_key *)_key;
address_module = key->address_module;
local = key->local;
peer = key->peer;
}
return gAddressModule->hash_address_pair(local, peer) % range;
return address_module->hash_address_pair(local, peer) % range;
}
@@ -396,8 +439,8 @@ EndpointManager::_EndpointCompare(void *_endpoint, const void *_key)
const endpoint_key *key = (endpoint_key *)_key;
TCPEndpoint *endpoint = (TCPEndpoint *)_endpoint;
return gAddressModule->get_port((sockaddr *)&endpoint->socket->address)
== key->port ? 0 : 1;
return endpoint->AddressModule()->get_port(
(sockaddr *)&endpoint->socket->address) == key->port ? 0 : 1;
}
@@ -406,7 +449,8 @@ EndpointManager::_EndpointHash(void *_endpoint, const void *_key, uint32 range)
{
if (_endpoint != NULL) {
TCPEndpoint *endpoint = (TCPEndpoint *)_endpoint;
return gAddressModule->get_port((sockaddr *)&endpoint->socket->address) % range;
return endpoint->AddressModule()->get_port(
(sockaddr *)&endpoint->socket->address) % range;
}
const endpoint_key *key = (endpoint_key *)_key;
@@ -8,18 +8,24 @@
#ifndef ENDPOINT_MANAGER_H
#define ENDPOINT_MANAGER_H
#include "tcp.h"
#include <net_datalink.h>
#include <lock.h>
#include <util/DoublyLinkedList.h>
#include <util/khash.h>
#include <sys/socket.h>
struct net_address_module_info;
struct net_domain;
class TCPEndpoint;
class EndpointManager {
class EndpointManager : public DoublyLinkedListLinkImpl<EndpointManager> {
public:
EndpointManager();
EndpointManager(net_domain *domain);
~EndpointManager();
status_t InitCheck() const;
@@ -34,6 +40,13 @@ class EndpointManager {
status_t BindToEphemeral(TCPEndpoint *endpoint);
status_t Unbind(TCPEndpoint *endpoint);
status_t ReplyWithReset(tcp_segment_header &segment,
net_buffer *buffer);
net_domain *Domain() const { return fDomain; }
net_address_module_info *AddressModule() const
{ return Domain()->address_module; }
private:
TCPEndpoint *_LookupConnection(sockaddr *local, sockaddr *peer);
status_t _RemoveConnection(TCPEndpoint *endpoint);
@@ -45,6 +58,8 @@ class EndpointManager {
static int _EndpointCompare(void *_endpoint, const void *_key);
static uint32 _EndpointHash(void *_endpoint, const void *_key, uint32 range);
net_domain *fDomain;
hash_table *fConnectionHash;
hash_table *fEndpointHash;
recursive_lock fLock;
@@ -158,6 +158,7 @@ WaitList::Signal()
TCPEndpoint::TCPEndpoint(net_socket *socket)
:
fManager(NULL),
fReceiveList("tcp receive"),
fSendList("tcp send"),
fOptions(0),
@@ -205,7 +206,10 @@ TCPEndpoint::~TCPEndpoint()
gStackModule->cancel_timer(&fDelayedAcknowledgeTimer);
gStackModule->cancel_timer(&fTimeWaitTimer);
gEndpointManager->Unbind(this);
if (fManager) {
fManager->Unbind(this);
return_endpoint_manager(fManager);
}
recursive_lock_destroy(&fLock);
}
@@ -234,7 +238,14 @@ status_t
TCPEndpoint::Open()
{
TRACE("Open()");
// nothing to do here...
if (Domain() == NULL || AddressModule() == NULL)
return EAFNOSUPPORT;
fManager = create_endpoint_manager(Domain());
if (fManager == NULL)
return EAFNOSUPPORT;
return B_OK;
}
@@ -304,7 +315,7 @@ status_t
TCPEndpoint::Connect(const struct sockaddr *address)
{
TRACE("Connect() on address %s",
AddressString(gDomain, address, true).Data());
AddressString(Domain(), address, true).Data());
RecursiveLocker locker(&fLock);
@@ -319,14 +330,14 @@ TCPEndpoint::Connect(const struct sockaddr *address)
// get a net_route if there isn't one
// TODO: get a net_route_info instead!
if (fRoute == NULL) {
fRoute = gDatalinkModule->get_route(gDomain, (sockaddr *)address);
fRoute = gDatalinkModule->get_route(Domain(), (sockaddr *)address);
TRACE(" Connect(): Using Route %p", fRoute);
if (fRoute == NULL)
return ENETUNREACH;
}
// make sure connection does not already exist
status_t status = gEndpointManager->SetConnection(this,
status_t status = fManager->SetConnection(this,
(sockaddr *)&socket->address, address, fRoute->interface->address);
if (status < B_OK) {
TRACE(" Connect(): could not add connection: %s!", strerror(status));
@@ -413,7 +424,7 @@ TCPEndpoint::Bind(sockaddr *address)
return B_BAD_VALUE;
TRACE("Bind() on address %s",
AddressString(gDomain, address, true).Data());
AddressString(Domain(), address, true).Data());
RecursiveLocker lock(fLock);
@@ -425,13 +436,13 @@ TCPEndpoint::Bind(sockaddr *address)
if (status < B_OK)
return status;
if (gAddressModule->get_port(address) == 0)
status = gEndpointManager->BindToEphemeral(this);
if (AddressModule()->get_port(address) == 0)
status = fManager->BindToEphemeral(this);
else
status = gEndpointManager->Bind(this);
status = fManager->Bind(this);
TRACE(" Bind() bound to %s (status %i)",
AddressString(gDomain, (sockaddr *)&socket->address, true).Data(),
AddressString(Domain(), (sockaddr *)&socket->address, true).Data(),
(int)status);
return status;
@@ -444,7 +455,7 @@ TCPEndpoint::Unbind(struct sockaddr *address)
TRACE("Unbind()");
RecursiveLocker lock(fLock);
return gEndpointManager->Unbind(this);
return fManager->Unbind(this);
}
@@ -646,7 +657,15 @@ TCPEndpoint::ReadAvailable()
bool
TCPEndpoint::IsBound() const
{
return !gAddressModule->is_empty_address((sockaddr *)&socket->address, true);
return !AddressModule()->is_empty_address((sockaddr *)&socket->address, true);
}
void
TCPEndpoint::DeleteSocket()
{
// the next call will delete `this'.
gSocketModule->delete_socket(socket);
}
@@ -723,9 +742,9 @@ TCPEndpoint::ListenReceive(tcp_segment_header &segment, net_buffer *buffer)
if (gSocketModule->spawn_pending_socket(socket, &newSocket) < B_OK)
return DROP;
gAddressModule->set_to((sockaddr *)&newSocket->address,
AddressModule()->set_to((sockaddr *)&newSocket->address,
(sockaddr *)&buffer->destination);
gAddressModule->set_to((sockaddr *)&newSocket->peer,
AddressModule()->set_to((sockaddr *)&newSocket->peer,
(sockaddr *)&buffer->source);
TCPEndpoint *endpoint = (TCPEndpoint *)newSocket->first_protocol;
@@ -734,12 +753,12 @@ TCPEndpoint::ListenReceive(tcp_segment_header &segment, net_buffer *buffer)
// TODO: proper error handling!
endpoint->fRoute = gDatalinkModule->get_route(gDomain,
endpoint->fRoute = gDatalinkModule->get_route(Domain(),
(sockaddr *)&newSocket->peer);
if (endpoint->fRoute == NULL)
return DROP;
if (gEndpointManager->SetConnection(endpoint, (sockaddr *)&buffer->destination,
if (fManager->SetConnection(endpoint, (sockaddr *)&buffer->destination,
(sockaddr *)&buffer->source, NULL) < B_OK)
return DROP;
@@ -1085,8 +1104,8 @@ TCPEndpoint::_SendQueued(bool force)
return status;
}
gAddressModule->set_to((sockaddr *)&buffer->source, (sockaddr *)&socket->address);
gAddressModule->set_to((sockaddr *)&buffer->destination, (sockaddr *)&socket->peer);
AddressModule()->set_to((sockaddr *)&buffer->source, (sockaddr *)&socket->address);
AddressModule()->set_to((sockaddr *)&buffer->destination, (sockaddr *)&socket->peer);
uint32 size = buffer->size;
if (length > 0 && fSendNext + segmentLength == fSendQueue.LastSequence()) {
@@ -1108,10 +1127,10 @@ TCPEndpoint::_SendQueued(bool force)
TRACE("SendQueued() flags %x, buffer %p, size %lu, from address %s to %s",
segment.flags, buffer, buffer->size,
AddressString(gDomain, (sockaddr *)&buffer->source, true).Data(),
AddressString(gDomain, (sockaddr *)&buffer->destination, true).Data());
AddressString(Domain(), (sockaddr *)&buffer->source, true).Data(),
AddressString(Domain(), (sockaddr *)&buffer->destination, true).Data());
status = add_tcp_header(segment, buffer);
status = add_tcp_header(AddressModule(), segment, buffer);
if (status != B_OK) {
gBufferModule->free(buffer);
return status;
@@ -1525,6 +1544,6 @@ TCPEndpoint::_TimeWaitTimer(struct net_timer *timer, void *data)
if (recursive_lock_lock(&endpoint->Lock()) < B_OK)
return;
gSocketModule->delete_socket(endpoint->socket);
endpoint->DeleteSocket();
}
@@ -64,6 +64,8 @@ class TCPEndpoint : public net_protocol {
tcp_state State() const { return fState; }
bool IsBound() const;
void DeleteSocket();
status_t DelayedAcknowledge();
status_t SendAcknowledge();
status_t UpdateTimeWait();
@@ -72,6 +74,12 @@ class TCPEndpoint : public net_protocol {
net_buffer *buffer);
int32 Receive(tcp_segment_header& segment, net_buffer *buffer);
net_domain *Domain() const
{ return socket->first_protocol->module->get_domain(
socket->first_protocol); }
net_address_module_info *AddressModule() const
{ return Domain()->address_module; }
private:
friend class EndpointManager;
@@ -93,6 +101,8 @@ class TCPEndpoint : public net_protocol {
static void _PersistTimer(net_timer *timer, void *data);
static void _DelayedAcknowledgeTimer(net_timer *timer, void *data);
EndpointManager *fManager;
TCPEndpoint *fConnectionHashNext;
TCPEndpoint *fEndpointHashNext;
TCPEndpoint *fEndpointNextWithSamePort;
@@ -42,34 +42,56 @@
typedef NetBufferField<uint16, offsetof(tcp_header, checksum)> TCPChecksumField;
net_domain *gDomain;
net_address_module_info *gAddressModule;
net_buffer_module_info *gBufferModule;
net_datalink_module_info *gDatalinkModule;
net_socket_module_info *gSocketModule;
net_stack_module_info *gStackModule;
EndpointManager *gEndpointManager;
status_t
set_domain(net_interface *interface = NULL)
// TODO we need to think of a better way to do this. It would be
// nice if we registered a per EndpointManager receiving
// protocol cookie, so we don't have to go through the list
// for each segment.
typedef DoublyLinkedList<EndpointManager> EndpointManagerList;
static benaphore sEndpointManagersLock;
static EndpointManagerList sEndpointManagers;
static EndpointManager *
endpoint_manager_for(net_domain *domain)
{
if (gDomain == NULL) {
// domain and address module are not known yet, we copy them from
// the buffer's interface (if any):
if (interface == NULL || interface->domain == NULL)
gDomain = gStackModule->get_domain(AF_INET);
else
gDomain = interface->domain;
if (gDomain == NULL) {
// this shouldn't occur, of course, but who knows...
return B_BAD_VALUE;
}
gAddressModule = gDomain->address_module;
EndpointManagerList::Iterator iterator = sEndpointManagers.GetIterator();
while (iterator.HasNext()) {
EndpointManager *endpointManager = iterator.Next();
if (endpointManager->Domain() == domain)
return endpointManager;
}
return B_OK;
return NULL;
}
EndpointManager *
create_endpoint_manager(net_domain *domain)
{
EndpointManager *endpointManager = endpoint_manager_for(domain);
if (endpointManager)
return endpointManager;
endpointManager = new (std::nothrow) EndpointManager(domain);
if (endpointManager)
sEndpointManagers.Add(endpointManager);
return endpointManager;
}
void
return_endpoint_manager(EndpointManager *endpointManager)
{
// TODO when the connection and endpoint count reach zero
// we should remove the endpoint manager from the endpoints
// list and delete it.
}
@@ -125,7 +147,8 @@ add_options(tcp_segment_header &segment, uint8 *buffer, size_t bufferSize)
for \a flags, \a seq \a ack and \a advertisedWindow.
*/
status_t
add_tcp_header(tcp_segment_header &segment, net_buffer *buffer)
add_tcp_header(net_address_module_info *addressModule,
tcp_segment_header &segment, net_buffer *buffer)
{
buffer->protocol = IPPROTO_TCP;
@@ -138,8 +161,8 @@ add_tcp_header(tcp_segment_header &segment, net_buffer *buffer)
tcp_header &header = bufferHeader.Data();
header.source_port = gAddressModule->get_port((sockaddr *)&buffer->source);
header.destination_port = gAddressModule->get_port((sockaddr *)&buffer->destination);
header.source_port = addressModule->get_port((sockaddr *)&buffer->source);
header.destination_port = addressModule->get_port((sockaddr *)&buffer->destination);
header.sequence = htonl(segment.sequence);
header.acknowledge = (segment.flags & TCP_FLAG_ACKNOWLEDGE)
? htonl(segment.acknowledge) : 0;
@@ -161,7 +184,7 @@ add_tcp_header(tcp_segment_header &segment, net_buffer *buffer)
TRACE(("add_tcp_header(): buffer %p, flags 0x%x, seq %lu, ack %lu, win %u\n", buffer,
segment.flags, segment.sequence, segment.acknowledge, segment.advertised_window));
*TCPChecksumField(buffer) = Checksum::PseudoHeader(gAddressModule,
*TCPChecksumField(buffer) = Checksum::PseudoHeader(addressModule,
gBufferModule, buffer, IPPROTO_TCP);
return B_OK;
@@ -222,44 +245,6 @@ process_options(tcp_segment_header &segment, net_buffer *buffer, int32 size)
}
status_t
reply_with_reset(tcp_segment_header &segment, net_buffer *buffer)
{
TRACE(("TCP: Sending RST...\n"));
net_buffer *reply = gBufferModule->create(512);
if (reply == NULL)
return B_NO_MEMORY;
gAddressModule->set_to((sockaddr *)&reply->source,
(sockaddr *)&buffer->destination);
gAddressModule->set_to((sockaddr *)&reply->destination,
(sockaddr *)&buffer->source);
tcp_segment_header outSegment;
outSegment.flags = TCP_FLAG_RESET;
outSegment.sequence = 0;
outSegment.acknowledge = 0;
outSegment.advertised_window = 0;
outSegment.urgent_offset = 0;
if ((segment.flags & TCP_FLAG_ACKNOWLEDGE) == 0) {
outSegment.flags |= TCP_FLAG_ACKNOWLEDGE;
outSegment.acknowledge = segment.sequence + buffer->size;
} else
outSegment.sequence = segment.acknowledge;
status_t status = add_tcp_header(outSegment, reply);
if (status == B_OK)
status = gDomain->module->send_data(NULL, reply);
if (status != B_OK)
gBufferModule->free(reply);
return status;
}
const char *
name_for_state(tcp_state state)
{
@@ -350,9 +335,6 @@ tcp_uninit_protocol(net_protocol *protocol)
status_t
tcp_open(net_protocol *protocol)
{
if (gDomain == NULL && set_domain() != B_OK)
return B_ERROR;
return ((TCPEndpoint *)protocol)->Open();
}
@@ -497,9 +479,12 @@ tcp_receive_data(net_buffer *buffer)
{
TRACE(("TCP: Received buffer %p\n", buffer));
if (gDomain == NULL && set_domain(buffer->interface) != B_OK)
if (buffer->interface == NULL || buffer->interface->domain == NULL)
return B_ERROR;
net_domain *domain = buffer->interface->domain;
net_address_module_info *addressModule = domain->address_module;
NetBufferHeaderReader<tcp_header> bufferHeader(buffer);
if (bufferHeader.Status() < B_OK)
return bufferHeader.Status();
@@ -510,16 +495,17 @@ tcp_receive_data(net_buffer *buffer)
if (headerLength < sizeof(tcp_header))
return B_BAD_DATA;
if (Checksum::PseudoHeader(gAddressModule, gBufferModule, buffer,
if (Checksum::PseudoHeader(addressModule, gBufferModule, buffer,
IPPROTO_TCP) != 0)
return B_BAD_DATA;
gAddressModule->set_port((struct sockaddr *)&buffer->source, header.source_port);
gAddressModule->set_port((struct sockaddr *)&buffer->destination, header.destination_port);
addressModule->set_port((sockaddr *)&buffer->source, header.source_port);
addressModule->set_port((sockaddr *)&buffer->destination,
header.destination_port);
TRACE((" Looking for: peer %s, local %s\n",
AddressString(gDomain, (sockaddr *)&buffer->source, true).Data(),
AddressString(gDomain, (sockaddr *)&buffer->destination, true).Data()));
AddressString(domain, (sockaddr *)&buffer->source, true).Data(),
AddressString(domain, (sockaddr *)&buffer->destination, true).Data()));
//dump_tcp_header(header);
//gBufferModule->dump(buffer);
@@ -538,11 +524,17 @@ tcp_receive_data(net_buffer *buffer)
bufferHeader.Remove(headerLength);
// we no longer need to keep the header around
RecursiveLocker locker(gEndpointManager->Locker());
BenaphoreLocker _(sEndpointManagersLock);
EndpointManager *endpointManager = endpoint_manager_for(domain);
if (endpointManager == NULL)
return B_ERROR;
RecursiveLocker locker(endpointManager->Locker());
int32 segmentAction = DROP;
TCPEndpoint *endpoint = gEndpointManager->FindConnection(
(struct sockaddr *)&buffer->destination, (struct sockaddr *)&buffer->source);
TCPEndpoint *endpoint = endpointManager->FindConnection(
(sockaddr *)&buffer->destination, (sockaddr *)&buffer->source);
if (endpoint != NULL) {
RecursiveLocker locker(endpoint->Lock());
TRACE(("Endpoint %p in state %s\n", endpoint, name_for_state(endpoint->State())));
@@ -575,13 +567,13 @@ tcp_receive_data(net_buffer *buffer)
else if (segmentAction & ACKNOWLEDGE)
endpoint->DelayedAcknowledge();
else if (segmentAction & DELETE)
gSocketModule->delete_socket(endpoint->socket);
endpoint->DeleteSocket();
} else if ((segment.flags & TCP_FLAG_RESET) == 0)
segmentAction = DROP | RESET;
if (segmentAction & RESET) {
// send reset
reply_with_reset(segment, buffer);
endpointManager->ReplyWithReset(segment, buffer);
}
if (segmentAction & DROP)
gBufferModule->free(buffer);
@@ -611,52 +603,39 @@ tcp_error_reply(net_protocol *protocol, net_buffer *causedError, uint32 code,
static status_t
tcp_init()
{
status_t status;
status_t status = benaphore_init(&sEndpointManagersLock,
"endpoint managers lock");
gDomain = NULL;
gAddressModule = NULL;
gEndpointManager = new (std::nothrow) EndpointManager();
if (gEndpointManager == NULL)
return B_NO_MEMORY;
status = gEndpointManager->InitCheck();
if (status < B_OK)
goto err1;
return status;
status = gStackModule->register_domain_protocols(AF_INET, SOCK_STREAM, 0,
"network/protocols/tcp/v1",
"network/protocols/ipv4/v1",
NULL);
if (status < B_OK)
goto err1;
return status;
status = gStackModule->register_domain_protocols(AF_INET, SOCK_STREAM, IPPROTO_TCP,
"network/protocols/tcp/v1",
"network/protocols/ipv4/v1",
NULL);
if (status < B_OK)
goto err1;
return status;
status = gStackModule->register_domain_receiving_protocol(AF_INET, IPPROTO_TCP,
"network/protocols/tcp/v1");
if (status < B_OK)
goto err1;
return status;
return B_OK;
err1:
delete gEndpointManager;
TRACE(("init_tcp() fails with %lx (%s)\n", status, strerror(status)));
return status;
}
static status_t
tcp_uninit()
{
delete gEndpointManager;
benaphore_destroy(&sEndpointManagersLock);
return B_OK;
}
@@ -157,17 +157,18 @@ enum tcp_segment_action {
};
extern net_domain *gDomain;
extern net_address_module_info *gAddressModule;
extern net_buffer_module_info *gBufferModule;
extern net_datalink_module_info *gDatalinkModule;
extern net_socket_module_info *gSocketModule;
extern net_stack_module_info *gStackModule;
extern EndpointManager *gEndpointManager;
status_t add_tcp_header(tcp_segment_header &segment, net_buffer *buffer);
status_t add_tcp_header(net_address_module_info *addressModule,
tcp_segment_header &segment, net_buffer *buffer);
const char *name_for_state(tcp_state state);
EndpointManager *create_endpoint_manager(net_domain *domain);
void return_endpoint_manager(EndpointManager *);
#endif // TCP_H