* Merged _Receive() and _SegmentReceived().
* Cleanup, shuffled methods around, renamed methods, etc. - no functional changes. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25223 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
e6fc462cb3
commit
db4b6bc46c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2006-2008, Haiku, Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
@ -14,53 +14,61 @@
|
||||
#include <util/DoublyLinkedList.h>
|
||||
|
||||
|
||||
typedef DoublyLinkedList<struct net_buffer, DoublyLinkedListCLink<struct net_buffer> > SegmentList;
|
||||
typedef DoublyLinkedList<struct net_buffer,
|
||||
DoublyLinkedListCLink<struct net_buffer> > SegmentList;
|
||||
|
||||
class BufferQueue {
|
||||
public:
|
||||
BufferQueue(size_t maxBytes);
|
||||
~BufferQueue();
|
||||
public:
|
||||
BufferQueue(size_t maxBytes);
|
||||
~BufferQueue();
|
||||
|
||||
void SetMaxBytes(size_t maxBytes);
|
||||
void SetInitialSequence(tcp_sequence sequence);
|
||||
void SetMaxBytes(size_t maxBytes);
|
||||
void SetInitialSequence(tcp_sequence sequence);
|
||||
|
||||
void Add(net_buffer *buffer);
|
||||
void Add(net_buffer *buffer, tcp_sequence sequence);
|
||||
status_t RemoveUntil(tcp_sequence sequence);
|
||||
status_t Get(net_buffer *buffer, tcp_sequence sequence, size_t bytes);
|
||||
status_t Get(size_t bytes, bool remove, net_buffer **_buffer);
|
||||
void Add(net_buffer* buffer);
|
||||
void Add(net_buffer* buffer, tcp_sequence sequence);
|
||||
status_t RemoveUntil(tcp_sequence sequence);
|
||||
status_t Get(net_buffer* buffer, tcp_sequence sequence,
|
||||
size_t bytes);
|
||||
status_t Get(size_t bytes, bool remove,
|
||||
net_buffer** _buffer);
|
||||
|
||||
size_t Available() const { return fContiguousBytes; }
|
||||
size_t Available(tcp_sequence sequence) const;
|
||||
size_t Available() const { return fContiguousBytes; }
|
||||
size_t Available(tcp_sequence sequence) const;
|
||||
|
||||
size_t PushedData() const
|
||||
{
|
||||
// we must check if fPushPointer is not 0 here due to
|
||||
// `tcp_sequence's special handling of >
|
||||
return fPushPointer != 0 && fPushPointer > fFirstSequence ?
|
||||
fPushPointer - fFirstSequence : 0;
|
||||
}
|
||||
inline size_t PushedData() const;
|
||||
void SetPushPointer();
|
||||
|
||||
void SetPushPointer();
|
||||
size_t Used() const { return fNumBytes; }
|
||||
size_t Free() const { return fMaxBytes - fNumBytes; }
|
||||
size_t Size() const { return fMaxBytes; }
|
||||
|
||||
size_t Used() const { return fNumBytes; }
|
||||
size_t Free() const { return fMaxBytes - fNumBytes; }
|
||||
size_t Size() const { return fMaxBytes; }
|
||||
bool IsContiguous() const
|
||||
{ return fNumBytes == fContiguousBytes; }
|
||||
|
||||
bool IsContiguous() const { return fNumBytes == fContiguousBytes; }
|
||||
tcp_sequence FirstSequence() const { return fFirstSequence; }
|
||||
tcp_sequence LastSequence() const { return fLastSequence; }
|
||||
tcp_sequence NextSequence() const
|
||||
{ return fFirstSequence + fContiguousBytes; }
|
||||
|
||||
tcp_sequence FirstSequence() const { return fFirstSequence; }
|
||||
tcp_sequence LastSequence() const { return fLastSequence; }
|
||||
tcp_sequence NextSequence() const { return fFirstSequence + fContiguousBytes; }
|
||||
|
||||
private:
|
||||
SegmentList fList;
|
||||
size_t fMaxBytes;
|
||||
size_t fNumBytes;
|
||||
size_t fContiguousBytes;
|
||||
tcp_sequence fFirstSequence;
|
||||
tcp_sequence fLastSequence;
|
||||
tcp_sequence fPushPointer;
|
||||
private:
|
||||
SegmentList fList;
|
||||
size_t fMaxBytes;
|
||||
size_t fNumBytes;
|
||||
size_t fContiguousBytes;
|
||||
tcp_sequence fFirstSequence;
|
||||
tcp_sequence fLastSequence;
|
||||
tcp_sequence fPushPointer;
|
||||
};
|
||||
|
||||
|
||||
size_t
|
||||
BufferQueue::PushedData() const
|
||||
{
|
||||
// we must check if fPushPointer is not 0 here due to
|
||||
// tcp_sequence's special handling of >
|
||||
return fPushPointer != 0
|
||||
&& fPushPointer > fFirstSequence ? fPushPointer - fFirstSequence : 0;
|
||||
}
|
||||
|
||||
#endif // BUFFER_QUEUE_H
|
||||
|
@ -479,7 +479,7 @@ EndpointManager::ReplyWithReset(tcp_segment_header &segment,
|
||||
|
||||
|
||||
void
|
||||
EndpointManager::DumpEndpoints() const
|
||||
EndpointManager::Dump() const
|
||||
{
|
||||
kprintf("-------- TCP Domain %p ---------\n", this);
|
||||
kprintf("%10s %20s %20s %8s %8s %12s\n", "address", "local", "peer",
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006-2007, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2006-2008, Haiku, Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
@ -27,25 +27,27 @@ struct net_domain;
|
||||
class EndpointManager;
|
||||
class TCPEndpoint;
|
||||
|
||||
|
||||
struct ConnectionHashDefinition {
|
||||
public:
|
||||
typedef std::pair<const sockaddr *, const sockaddr *> KeyType;
|
||||
typedef std::pair<const sockaddr*, const sockaddr*> KeyType;
|
||||
typedef TCPEndpoint ValueType;
|
||||
|
||||
ConnectionHashDefinition(EndpointManager *manager);
|
||||
ConnectionHashDefinition(EndpointManager* manager);
|
||||
ConnectionHashDefinition(
|
||||
const ConnectionHashDefinition& definition)
|
||||
: fManager(definition.fManager)
|
||||
{
|
||||
}
|
||||
|
||||
ConnectionHashDefinition(const ConnectionHashDefinition& definition)
|
||||
: fManager(definition.fManager)
|
||||
{
|
||||
}
|
||||
|
||||
size_t HashKey(const KeyType &key) const;
|
||||
size_t Hash(TCPEndpoint *endpoint) const;
|
||||
bool Compare(const KeyType &key, TCPEndpoint *endpoint) const;
|
||||
HashTableLink<TCPEndpoint> *GetLink(TCPEndpoint *endpoint) const;
|
||||
size_t HashKey(const KeyType& key) const;
|
||||
size_t Hash(TCPEndpoint* endpoint) const;
|
||||
bool Compare(const KeyType& key,
|
||||
TCPEndpoint* endpoint) const;
|
||||
HashTableLink<TCPEndpoint>* GetLink(TCPEndpoint* endpoint) const;
|
||||
|
||||
private:
|
||||
EndpointManager *fManager;
|
||||
EndpointManager* fManager;
|
||||
};
|
||||
|
||||
|
||||
@ -54,57 +56,61 @@ public:
|
||||
typedef uint16 KeyType;
|
||||
typedef TCPEndpoint ValueType;
|
||||
|
||||
size_t HashKey(uint16 port) const;
|
||||
size_t Hash(TCPEndpoint *endpoint) const;
|
||||
bool Compare(uint16 port, TCPEndpoint *endpoint) const;
|
||||
bool CompareValues(TCPEndpoint *first, TCPEndpoint *second) const;
|
||||
HashTableLink<TCPEndpoint> *GetLink(TCPEndpoint *endpoint) const;
|
||||
size_t HashKey(uint16 port) const;
|
||||
size_t Hash(TCPEndpoint* endpoint) const;
|
||||
bool Compare(uint16 port, TCPEndpoint* endpoint) const;
|
||||
bool CompareValues(TCPEndpoint* first,
|
||||
TCPEndpoint* second) const;
|
||||
HashTableLink<TCPEndpoint>* GetLink(TCPEndpoint* endpoint) const;
|
||||
};
|
||||
|
||||
|
||||
class EndpointManager : public DoublyLinkedListLinkImpl<EndpointManager> {
|
||||
public:
|
||||
EndpointManager(net_domain *domain);
|
||||
~EndpointManager();
|
||||
public:
|
||||
EndpointManager(net_domain* domain);
|
||||
~EndpointManager();
|
||||
|
||||
status_t InitCheck() const;
|
||||
status_t InitCheck() const;
|
||||
|
||||
TCPEndpoint *FindConnection(sockaddr *local, sockaddr *peer);
|
||||
TCPEndpoint* FindConnection(sockaddr* local, sockaddr* peer);
|
||||
|
||||
status_t SetConnection(TCPEndpoint *endpoint, const sockaddr *local,
|
||||
const sockaddr *peer, const sockaddr *interfaceLocal);
|
||||
status_t SetPassive(TCPEndpoint *endpoint);
|
||||
status_t SetConnection(TCPEndpoint* endpoint,
|
||||
const sockaddr* local, const sockaddr* peer,
|
||||
const sockaddr* interfaceLocal);
|
||||
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 Bind(TCPEndpoint* endpoint,
|
||||
const sockaddr* address);
|
||||
status_t BindChild(TCPEndpoint* endpoint);
|
||||
status_t Unbind(TCPEndpoint* endpoint);
|
||||
|
||||
status_t ReplyWithReset(tcp_segment_header &segment,
|
||||
net_buffer *buffer);
|
||||
status_t ReplyWithReset(tcp_segment_header& segment,
|
||||
net_buffer* buffer);
|
||||
|
||||
void DumpEndpoints() const;
|
||||
net_domain* Domain() const { return fDomain; }
|
||||
net_address_module_info* AddressModule() const
|
||||
{ return Domain()->address_module; }
|
||||
|
||||
net_domain *Domain() const { return fDomain; }
|
||||
net_address_module_info *AddressModule() const
|
||||
{ return Domain()->address_module; }
|
||||
void Dump() const;
|
||||
|
||||
private:
|
||||
TCPEndpoint *_LookupConnection(const sockaddr *local,
|
||||
const sockaddr *peer);
|
||||
status_t _Bind(TCPEndpoint *endpoint, const sockaddr *address);
|
||||
status_t _BindToAddress(TCPEndpoint *endpoint, const sockaddr *address);
|
||||
status_t _BindToEphemeral(TCPEndpoint *endpoint,
|
||||
const sockaddr *address);
|
||||
private:
|
||||
TCPEndpoint* _LookupConnection(const sockaddr* local,
|
||||
const sockaddr* peer);
|
||||
status_t _Bind(TCPEndpoint* endpoint,
|
||||
const sockaddr* address);
|
||||
status_t _BindToAddress(TCPEndpoint* endpoint,
|
||||
const sockaddr* address);
|
||||
status_t _BindToEphemeral(TCPEndpoint* endpoint,
|
||||
const sockaddr* address);
|
||||
|
||||
net_domain *fDomain;
|
||||
typedef OpenHashTable<ConnectionHashDefinition> ConnectionTable;
|
||||
typedef MultiHashTable<EndpointHashDefinition> EndpointTable;
|
||||
|
||||
typedef OpenHashTable<ConnectionHashDefinition> ConnectionTable;
|
||||
typedef MultiHashTable<EndpointHashDefinition> EndpointTable;
|
||||
|
||||
ConnectionTable fConnectionHash;
|
||||
EndpointTable fEndpointHash;
|
||||
uint16 fLastPort;
|
||||
benaphore fLock;
|
||||
benaphore fLock;
|
||||
net_domain* fDomain;
|
||||
ConnectionTable fConnectionHash;
|
||||
EndpointTable fEndpointHash;
|
||||
uint16 fLastPort;
|
||||
};
|
||||
|
||||
#endif // ENDPOINT_MANAGER_H
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -43,94 +43,101 @@ private:
|
||||
|
||||
class TCPEndpoint : public net_protocol, public ProtocolSocket {
|
||||
public:
|
||||
TCPEndpoint(net_socket *socket);
|
||||
~TCPEndpoint();
|
||||
TCPEndpoint(net_socket* socket);
|
||||
~TCPEndpoint();
|
||||
|
||||
status_t InitCheck() const;
|
||||
status_t InitCheck() const;
|
||||
|
||||
status_t Open();
|
||||
status_t Close();
|
||||
status_t Free();
|
||||
status_t Connect(const struct sockaddr *address);
|
||||
status_t Accept(struct net_socket **_acceptedSocket);
|
||||
status_t Bind(const sockaddr *address);
|
||||
status_t Unbind(struct sockaddr *address);
|
||||
status_t Listen(int count);
|
||||
status_t Shutdown(int direction);
|
||||
status_t SendData(net_buffer *buffer);
|
||||
ssize_t SendAvailable();
|
||||
status_t ReadData(size_t numBytes, uint32 flags, net_buffer **_buffer);
|
||||
ssize_t ReadAvailable();
|
||||
status_t Open();
|
||||
status_t Close();
|
||||
status_t Free();
|
||||
status_t Connect(const struct sockaddr* address);
|
||||
status_t Accept(struct net_socket** _acceptedSocket);
|
||||
status_t Bind(const sockaddr* address);
|
||||
status_t Unbind(struct sockaddr* address);
|
||||
status_t Listen(int count);
|
||||
status_t Shutdown(int direction);
|
||||
status_t SendData(net_buffer* buffer);
|
||||
ssize_t SendAvailable();
|
||||
status_t ReadData(size_t numBytes, uint32 flags,
|
||||
net_buffer** _buffer);
|
||||
ssize_t ReadAvailable();
|
||||
|
||||
status_t FillStat(struct net_stat *stat);
|
||||
status_t FillStat(struct net_stat* stat);
|
||||
|
||||
status_t SetSendBufferSize(size_t length);
|
||||
status_t SetReceiveBufferSize(size_t length);
|
||||
status_t SetSendBufferSize(size_t length);
|
||||
status_t SetReceiveBufferSize(size_t length);
|
||||
|
||||
status_t SetOption(int option, const void *value, int length);
|
||||
status_t SetOption(int option, const void* value, int length);
|
||||
|
||||
tcp_state State() const { return fState; }
|
||||
bool IsBound() const;
|
||||
tcp_state State() const { return fState; }
|
||||
bool IsBound() const;
|
||||
|
||||
status_t DelayedAcknowledge();
|
||||
status_t SendAcknowledge(bool force);
|
||||
status_t UpdateTimeWait();
|
||||
status_t DelayedAcknowledge();
|
||||
status_t SendAcknowledge(bool force);
|
||||
|
||||
int32 SegmentReceived(tcp_segment_header& segment, net_buffer *buffer);
|
||||
int32 Spawn(TCPEndpoint *parent, tcp_segment_header& segment,
|
||||
net_buffer *buffer);
|
||||
int32 SegmentReceived(tcp_segment_header& segment,
|
||||
net_buffer* buffer);
|
||||
|
||||
void DumpInternalState() const;
|
||||
void Dump() const;
|
||||
|
||||
private:
|
||||
friend class EndpointManager;
|
||||
void _StartPersistTimer();
|
||||
void _EnterTimeWait();
|
||||
status_t _UpdateTimeWait();
|
||||
void _CancelConnectionTimers();
|
||||
uint8 _CurrentFlags();
|
||||
bool _ShouldSendSegment(tcp_segment_header& segment,
|
||||
uint32 length, uint32 segmentMaxSize,
|
||||
uint32 flightSize);
|
||||
status_t _SendQueued(bool force = false);
|
||||
status_t _SendQueued(bool force, uint32 sendWindow);
|
||||
int _MaxSegmentSize(const struct sockaddr* address) const;
|
||||
status_t _Disconnect(bool closing);
|
||||
ssize_t _AvailableData() const;
|
||||
void _NotifyReader();
|
||||
bool _ShouldReceive() const;
|
||||
void _HandleReset(status_t error);
|
||||
int32 _Spawn(TCPEndpoint* parent, tcp_segment_header& segment,
|
||||
net_buffer* buffer);
|
||||
int32 _ListenReceive(tcp_segment_header& segment,
|
||||
net_buffer* buffer);
|
||||
int32 _SynchronizeSentReceive(tcp_segment_header& segment,
|
||||
net_buffer* buffer);
|
||||
int32 _SegmentReceived(tcp_segment_header& segment,
|
||||
net_buffer* buffer);
|
||||
int32 _Receive(tcp_segment_header& segment,
|
||||
net_buffer* buffer);
|
||||
void _UpdateTimestamps(tcp_segment_header& segment,
|
||||
size_t segmentLength);
|
||||
void _MarkEstablished();
|
||||
status_t _WaitForEstablished(MutexLocker& lock,
|
||||
bigtime_t timeout);
|
||||
bool _AddData(tcp_segment_header& segment,
|
||||
net_buffer* buffer);
|
||||
void _PrepareReceivePath(tcp_segment_header& segment);
|
||||
status_t _PrepareSendPath(const sockaddr* peer);
|
||||
void _Acknowledged(tcp_segment_header& segment);
|
||||
void _Retransmit();
|
||||
void _UpdateRoundTripTime(int32 roundTripTime);
|
||||
void _ResetSlowStart();
|
||||
void _DuplicateAcknowledge(tcp_segment_header& segment);
|
||||
|
||||
void _StartPersistTimer();
|
||||
void _EnterTimeWait();
|
||||
void _CancelConnectionTimers();
|
||||
uint8 _CurrentFlags();
|
||||
bool _ShouldSendSegment(tcp_segment_header &segment, uint32 length,
|
||||
uint32 segmentMaxSize, uint32 flightSize);
|
||||
status_t _SendQueued(bool force = false);
|
||||
status_t _SendQueued(bool force, uint32 sendWindow);
|
||||
int _MaxSegmentSize(const struct sockaddr *) const;
|
||||
status_t _Shutdown(bool closing);
|
||||
ssize_t _AvailableData() const;
|
||||
void _NotifyReader();
|
||||
bool _ShouldReceive() const;
|
||||
void _HandleReset(status_t error);
|
||||
int32 _ListenReceive(tcp_segment_header& segment, net_buffer *buffer);
|
||||
int32 _SynchronizeSentReceive(tcp_segment_header& segment,
|
||||
net_buffer *buffer);
|
||||
int32 _SegmentReceived(tcp_segment_header& segment, net_buffer *buffer);
|
||||
int32 _Receive(tcp_segment_header& segment, net_buffer *buffer);
|
||||
void _UpdateTimestamps(tcp_segment_header& segment,
|
||||
size_t segmentLength);
|
||||
void _MarkEstablished();
|
||||
status_t _WaitForEstablished(MutexLocker &lock, bigtime_t timeout);
|
||||
bool _AddData(tcp_segment_header &segment, net_buffer *buffer);
|
||||
void _PrepareReceivePath(tcp_segment_header &segment);
|
||||
status_t _PrepareSendPath(const sockaddr *peer);
|
||||
void _Acknowledged(tcp_segment_header &segment);
|
||||
void _Retransmit();
|
||||
void _UpdateSRTT(int32 roundTripTime);
|
||||
void _ResetSlowStart();
|
||||
void _DuplicateAcknowledge(tcp_segment_header &segment);
|
||||
|
||||
static void _TimeWaitTimer(net_timer *timer, void *data);
|
||||
static void _RetransmitTimer(net_timer *timer, void *data);
|
||||
static void _PersistTimer(net_timer *timer, void *data);
|
||||
static void _DelayedAcknowledgeTimer(net_timer *timer, void *data);
|
||||
|
||||
EndpointManager *fManager;
|
||||
static void _TimeWaitTimer(net_timer* timer, void* _endpoint);
|
||||
static void _RetransmitTimer(net_timer* timer, void* _endpoint);
|
||||
static void _PersistTimer(net_timer* timer, void* _endpoint);
|
||||
static void _DelayedAcknowledgeTimer(net_timer* timer,
|
||||
void* _endpoint);
|
||||
|
||||
private:
|
||||
HashTableLink<TCPEndpoint> fConnectionHashLink;
|
||||
HashTableLink<TCPEndpoint> fEndpointHashLink;
|
||||
|
||||
friend class EndpointManager;
|
||||
friend class ConnectionHashDefinition;
|
||||
friend class EndpointHashDefinition;
|
||||
|
||||
mutex fLock;
|
||||
EndpointManager* fManager;
|
||||
WaitList fReceiveList;
|
||||
WaitList fSendList;
|
||||
sem_id fAcceptSemaphore;
|
||||
|
@ -77,30 +77,6 @@ endpoint_manager_for(net_domain *domain)
|
||||
}
|
||||
|
||||
|
||||
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.
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
bump_option(tcp_option *&option, size_t &length)
|
||||
{
|
||||
@ -189,8 +165,181 @@ add_options(tcp_segment_header &segment, uint8 *buffer, size_t bufferSize)
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Constructs a TCP header on \a buffer with the specified values
|
||||
static void
|
||||
process_options(tcp_segment_header &segment, net_buffer *buffer, size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return;
|
||||
|
||||
tcp_option *option;
|
||||
|
||||
uint8 optionsBuffer[kMaxOptionSize];
|
||||
if (gBufferModule->direct_access(buffer, sizeof(tcp_header), size,
|
||||
(void **)&option) != B_OK) {
|
||||
if (size > sizeof(optionsBuffer)) {
|
||||
dprintf("Ignoring TCP options larger than expected.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
gBufferModule->read(buffer, sizeof(tcp_header), optionsBuffer, size);
|
||||
option = (tcp_option *)optionsBuffer;
|
||||
}
|
||||
|
||||
while (size > 0) {
|
||||
int32 length = -1;
|
||||
|
||||
switch (option->kind) {
|
||||
case TCP_OPTION_END:
|
||||
case TCP_OPTION_NOP:
|
||||
length = 1;
|
||||
break;
|
||||
case TCP_OPTION_MAX_SEGMENT_SIZE:
|
||||
if (option->length == 4 && (size - 4) >= 0)
|
||||
segment.max_segment_size = ntohs(option->max_segment_size);
|
||||
break;
|
||||
case TCP_OPTION_WINDOW_SHIFT:
|
||||
if (option->length == 3 && (size - 3) >= 0) {
|
||||
segment.options |= TCP_HAS_WINDOW_SCALE;
|
||||
segment.window_shift = option->window_shift;
|
||||
}
|
||||
break;
|
||||
case TCP_OPTION_TIMESTAMP:
|
||||
if (option->length == 10 && (size - 10) >= 0) {
|
||||
segment.options |= TCP_HAS_TIMESTAMPS;
|
||||
segment.timestamp_value = option->timestamp.value;
|
||||
segment.timestamp_reply =
|
||||
ntohl(option->timestamp.reply);
|
||||
}
|
||||
break;
|
||||
case TCP_OPTION_SACK_PERMITTED:
|
||||
if (option->length == 2 && (size - 2) >= 0)
|
||||
segment.options |= TCP_SACK_PERMITTED;
|
||||
}
|
||||
|
||||
if (length < 0) {
|
||||
length = option->length;
|
||||
if (length == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
size -= length;
|
||||
option = (tcp_option *)((uint8 *)option + length);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
static void
|
||||
dump_tcp_header(tcp_header &header)
|
||||
{
|
||||
dprintf(" source port: %u\n", ntohs(header.source_port));
|
||||
dprintf(" dest port: %u\n", ntohs(header.destination_port));
|
||||
dprintf(" sequence: %lu\n", header.Sequence());
|
||||
dprintf(" ack: %lu\n", header.Acknowledge());
|
||||
dprintf(" flags: %s%s%s%s%s%s\n", (header.flags & TCP_FLAG_FINISH) ? "FIN " : "",
|
||||
(header.flags & TCP_FLAG_SYNCHRONIZE) ? "SYN " : "",
|
||||
(header.flags & TCP_FLAG_RESET) ? "RST " : "",
|
||||
(header.flags & TCP_FLAG_PUSH) ? "PUSH " : "",
|
||||
(header.flags & TCP_FLAG_ACKNOWLEDGE) ? "ACK " : "",
|
||||
(header.flags & TCP_FLAG_URGENT) ? "URG " : "");
|
||||
dprintf(" window: %u\n", header.AdvertisedWindow());
|
||||
dprintf(" urgent offset: %u\n", header.UrgentOffset());
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static int
|
||||
dump_endpoints(int argc, char** argv)
|
||||
{
|
||||
EndpointManagerList::Iterator iterator = sEndpointManagers.GetIterator();
|
||||
|
||||
while (iterator.HasNext())
|
||||
iterator.Next()->Dump();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
dump_endpoint(int argc, char** argv)
|
||||
{
|
||||
if (argc < 2) {
|
||||
kprintf("usage: tcp_endpoint [address]\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
TCPEndpoint* endpoint = (TCPEndpoint*)parse_expression(argv[1]);
|
||||
endpoint->Dump();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - internal API
|
||||
|
||||
|
||||
EndpointManager*
|
||||
get_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
|
||||
put_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.
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
name_for_state(tcp_state state)
|
||||
{
|
||||
switch (state) {
|
||||
case CLOSED:
|
||||
return "closed";
|
||||
case LISTEN:
|
||||
return "listen";
|
||||
case SYNCHRONIZE_SENT:
|
||||
return "syn-sent";
|
||||
case SYNCHRONIZE_RECEIVED:
|
||||
return "syn-received";
|
||||
case ESTABLISHED:
|
||||
return "established";
|
||||
|
||||
// peer closes the connection
|
||||
case FINISH_RECEIVED:
|
||||
return "close-wait";
|
||||
case WAIT_FOR_FINISH_ACKNOWLEDGE:
|
||||
return "last-ack";
|
||||
|
||||
// we close the connection
|
||||
case FINISH_SENT:
|
||||
return "fin-wait1";
|
||||
case FINISH_ACKNOWLEDGED:
|
||||
return "fin-wait2";
|
||||
case CLOSING:
|
||||
return "closing";
|
||||
|
||||
case TIME_WAIT:
|
||||
return "time-wait";
|
||||
}
|
||||
|
||||
return "-";
|
||||
}
|
||||
|
||||
|
||||
/*! Constructs a TCP header on \a buffer with the specified values
|
||||
for \a flags, \a seq \a ack and \a advertisedWindow.
|
||||
*/
|
||||
status_t
|
||||
@ -268,153 +417,6 @@ tcp_options_length(tcp_segment_header &segment)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
process_options(tcp_segment_header &segment, net_buffer *buffer, size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return;
|
||||
|
||||
tcp_option *option;
|
||||
|
||||
uint8 optionsBuffer[kMaxOptionSize];
|
||||
if (gBufferModule->direct_access(buffer, sizeof(tcp_header), size,
|
||||
(void **)&option) != B_OK) {
|
||||
if (size > sizeof(optionsBuffer)) {
|
||||
dprintf("Ignoring TCP options larger than expected.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
gBufferModule->read(buffer, sizeof(tcp_header), optionsBuffer, size);
|
||||
option = (tcp_option *)optionsBuffer;
|
||||
}
|
||||
|
||||
while (size > 0) {
|
||||
int32 length = -1;
|
||||
|
||||
switch (option->kind) {
|
||||
case TCP_OPTION_END:
|
||||
case TCP_OPTION_NOP:
|
||||
length = 1;
|
||||
break;
|
||||
case TCP_OPTION_MAX_SEGMENT_SIZE:
|
||||
if (option->length == 4 && (size - 4) >= 0)
|
||||
segment.max_segment_size = ntohs(option->max_segment_size);
|
||||
break;
|
||||
case TCP_OPTION_WINDOW_SHIFT:
|
||||
if (option->length == 3 && (size - 3) >= 0) {
|
||||
segment.options |= TCP_HAS_WINDOW_SCALE;
|
||||
segment.window_shift = option->window_shift;
|
||||
}
|
||||
break;
|
||||
case TCP_OPTION_TIMESTAMP:
|
||||
if (option->length == 10 && (size - 10) >= 0) {
|
||||
segment.options |= TCP_HAS_TIMESTAMPS;
|
||||
segment.timestamp_value = option->timestamp.value;
|
||||
segment.timestamp_reply =
|
||||
ntohl(option->timestamp.reply);
|
||||
}
|
||||
break;
|
||||
case TCP_OPTION_SACK_PERMITTED:
|
||||
if (option->length == 2 && (size - 2) >= 0)
|
||||
segment.options |= TCP_SACK_PERMITTED;
|
||||
}
|
||||
|
||||
if (length < 0) {
|
||||
length = option->length;
|
||||
if (length == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
size -= length;
|
||||
option = (tcp_option *)((uint8 *)option + length);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
name_for_state(tcp_state state)
|
||||
{
|
||||
switch (state) {
|
||||
case CLOSED:
|
||||
return "closed";
|
||||
case LISTEN:
|
||||
return "listen";
|
||||
case SYNCHRONIZE_SENT:
|
||||
return "syn-sent";
|
||||
case SYNCHRONIZE_RECEIVED:
|
||||
return "syn-received";
|
||||
case ESTABLISHED:
|
||||
return "established";
|
||||
|
||||
// peer closes the connection
|
||||
case FINISH_RECEIVED:
|
||||
return "close-wait";
|
||||
case WAIT_FOR_FINISH_ACKNOWLEDGE:
|
||||
return "last-ack";
|
||||
|
||||
// we close the connection
|
||||
case FINISH_SENT:
|
||||
return "fin-wait1";
|
||||
case FINISH_ACKNOWLEDGED:
|
||||
return "fin-wait2";
|
||||
case CLOSING:
|
||||
return "closing";
|
||||
|
||||
case TIME_WAIT:
|
||||
return "time-wait";
|
||||
}
|
||||
|
||||
return "-";
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
static void
|
||||
dump_tcp_header(tcp_header &header)
|
||||
{
|
||||
dprintf(" source port: %u\n", ntohs(header.source_port));
|
||||
dprintf(" dest port: %u\n", ntohs(header.destination_port));
|
||||
dprintf(" sequence: %lu\n", header.Sequence());
|
||||
dprintf(" ack: %lu\n", header.Acknowledge());
|
||||
dprintf(" flags: %s%s%s%s%s%s\n", (header.flags & TCP_FLAG_FINISH) ? "FIN " : "",
|
||||
(header.flags & TCP_FLAG_SYNCHRONIZE) ? "SYN " : "",
|
||||
(header.flags & TCP_FLAG_RESET) ? "RST " : "",
|
||||
(header.flags & TCP_FLAG_PUSH) ? "PUSH " : "",
|
||||
(header.flags & TCP_FLAG_ACKNOWLEDGE) ? "ACK " : "",
|
||||
(header.flags & TCP_FLAG_URGENT) ? "URG " : "");
|
||||
dprintf(" window: %u\n", header.AdvertisedWindow());
|
||||
dprintf(" urgent offset: %u\n", header.UrgentOffset());
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static int
|
||||
dump_endpoints(int argc, char *argv[])
|
||||
{
|
||||
EndpointManagerList::Iterator it = sEndpointManagers.GetIterator();
|
||||
|
||||
while (it.HasNext())
|
||||
it.Next()->DumpEndpoints();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
dump_endpoint(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 2) {
|
||||
kprintf("usage: tcp_endpoint [address]\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
TCPEndpoint *endpoint = (TCPEndpoint *)strtoul(argv[1], NULL, 16);
|
||||
endpoint->DumpInternalState();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - protocol API
|
||||
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006-2007, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2006-2008, Haiku, Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
@ -72,24 +72,28 @@ struct tcp_header {
|
||||
} _PACKED;
|
||||
|
||||
class tcp_sequence {
|
||||
public:
|
||||
tcp_sequence() {}
|
||||
tcp_sequence(uint32 sequence) : number(sequence) {}
|
||||
public:
|
||||
tcp_sequence() {}
|
||||
tcp_sequence(uint32 sequence) : fNumber(sequence) {}
|
||||
|
||||
operator uint32() const { return number; }
|
||||
operator uint32() const { return fNumber; }
|
||||
|
||||
void operator=(uint32 sequence) { number = sequence; }
|
||||
bool operator>(uint32 sequence) const { return (int32)(number - sequence) > 0; }
|
||||
bool operator>=(uint32 sequence) const { return (int32)(number - sequence) >= 0; }
|
||||
bool operator<(uint32 sequence) const { return (int32)(number - sequence) < 0; }
|
||||
bool operator<=(uint32 sequence) const { return (int32)(number - sequence) <= 0; }
|
||||
void operator=(uint32 sequence) { fNumber = sequence; }
|
||||
bool operator>(uint32 sequence) const
|
||||
{ return (int32)(fNumber - sequence) > 0; }
|
||||
bool operator>=(uint32 sequence) const
|
||||
{ return (int32)(fNumber - sequence) >= 0; }
|
||||
bool operator<(uint32 sequence) const
|
||||
{ return (int32)(fNumber - sequence) < 0; }
|
||||
bool operator<=(uint32 sequence) const
|
||||
{ return (int32)(fNumber - sequence) <= 0; }
|
||||
|
||||
uint32& operator+=(uint32 sequence) { return number += sequence; }
|
||||
uint32& operator++() { return ++number; }
|
||||
uint32 operator++(int _) { return number++; }
|
||||
uint32& operator+=(uint32 sequence) { return fNumber += sequence; }
|
||||
uint32& operator++() { return ++fNumber; }
|
||||
uint32 operator++(int _) { return fNumber++; }
|
||||
|
||||
private:
|
||||
uint32 number;
|
||||
private:
|
||||
uint32 fNumber;
|
||||
};
|
||||
|
||||
// TCP flag constants
|
||||
@ -179,27 +183,28 @@ struct tcp_segment_header {
|
||||
};
|
||||
|
||||
enum tcp_segment_action {
|
||||
KEEP = 0x00,
|
||||
DROP = 0x01,
|
||||
RESET = 0x02,
|
||||
ACKNOWLEDGE = 0x04,
|
||||
KEEP = 0x00,
|
||||
DROP = 0x01,
|
||||
RESET = 0x02,
|
||||
ACKNOWLEDGE = 0x04,
|
||||
IMMEDIATE_ACKNOWLEDGE = 0x08,
|
||||
DELETE_ENDPOINT = 0x10,
|
||||
};
|
||||
|
||||
|
||||
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 net_buffer_module_info* gBufferModule;
|
||||
extern net_datalink_module_info* gDatalinkModule;
|
||||
extern net_socket_module_info* gSocketModule;
|
||||
extern net_stack_module_info* gStackModule;
|
||||
|
||||
|
||||
status_t add_tcp_header(net_address_module_info *addressModule,
|
||||
tcp_segment_header &segment, net_buffer *buffer);
|
||||
size_t tcp_options_length(tcp_segment_header &segment);
|
||||
EndpointManager* get_endpoint_manager(net_domain* domain);
|
||||
void put_endpoint_manager(EndpointManager* manager);
|
||||
|
||||
const char *name_for_state(tcp_state state);
|
||||
status_t add_tcp_header(net_address_module_info* addressModule,
|
||||
tcp_segment_header& segment, net_buffer* buffer);
|
||||
size_t tcp_options_length(tcp_segment_header& segment);
|
||||
|
||||
EndpointManager *create_endpoint_manager(net_domain *domain);
|
||||
void return_endpoint_manager(EndpointManager *);
|
||||
const char* name_for_state(tcp_state state);
|
||||
|
||||
#endif // TCP_H
|
||||
|
Loading…
Reference in New Issue
Block a user