The full TCP state machine should be working now, with the exception of the LISTEN state. It cannot yet transfer data though - that will be implemented next. Connections are only made from port 40000 though, ephemeral ports are not yet implemented.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18729 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -9,10 +9,16 @@
|
|||||||
// Initial estimate for packet round trip time (RTT)
|
// Initial estimate for packet round trip time (RTT)
|
||||||
#define TCP_INITIAL_RTT 120000000LL
|
#define TCP_INITIAL_RTT 120000000LL
|
||||||
|
|
||||||
|
// Estimate for Maximum segment lifetime in the internet
|
||||||
|
#define TCP_MAX_SEGMENT_LIFETIME TCP_INITIAL_RTT
|
||||||
|
|
||||||
// keep maximum buffer sizes < max net_buffer size for now
|
// keep maximum buffer sizes < max net_buffer size for now
|
||||||
#define TCP_MAX_SEND_BUF 0//1024
|
#define TCP_MAX_SEND_BUF 1024
|
||||||
#define TCP_MAX_RECV_BUF TCP_MAX_SEND_BUF
|
#define TCP_MAX_RECV_BUF TCP_MAX_SEND_BUF
|
||||||
|
|
||||||
|
#define TCP_IS_GOOD_ACK(x) (fLastByteAckd > fNextByteToSend ? ((x) >= fLastByteAckd || (x) <= fNextByteToSend) : ((x) >= fLastByteAckd && (x) <= fNextByteToSend))
|
||||||
|
#define TCP_IS_GOOD_SEQ(x,y) (fNextByteToRead < fNextByteToRead + TCP_MAX_RECV_BUF ? (x) >= fNextByteToRead && (x) + (y) <= fNextByteToRead + TCP_MAX_RECV_BUF : ((x) >= fNextByteToRead || (x) <= fNextByteToRead + TCP_MAX_RECV_BUF) && ((x) + (y) >= fNextByteToRead || (x) + (y) <= fNextByteToRead + TCP_MAX_RECV_BUF))
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const sockaddr *local;
|
const sockaddr *local;
|
||||||
const sockaddr *peer;
|
const sockaddr *peer;
|
||||||
@@ -59,13 +65,15 @@ private:
|
|||||||
bool fTimedOut;
|
bool fTimedOut;
|
||||||
};
|
};
|
||||||
|
|
||||||
status_t Send(uint16 flags);
|
status_t Send(uint16 flags, bool empty);
|
||||||
|
status_t Reset(uint32 sequenceNum, uint32 acknowledgeNum);
|
||||||
|
static void TimeWait(struct net_timer *timer, void *data);
|
||||||
|
|
||||||
uint32 fLastByteAckd;
|
uint32 fLastByteAckd;
|
||||||
uint32 fNextByteToSend;
|
uint32 fNextByteToSend;
|
||||||
uint32 fLastByteWritten;
|
uint32 fNextByteToWrite;
|
||||||
|
|
||||||
uint32 fLastByteRead;
|
uint32 fNextByteToRead;
|
||||||
uint32 fNextByteExpected;
|
uint32 fNextByteExpected;
|
||||||
uint32 fLastByteReceived;
|
uint32 fLastByteReceived;
|
||||||
|
|
||||||
@@ -78,7 +86,9 @@ private:
|
|||||||
|
|
||||||
TCPConnection *fHashLink;
|
TCPConnection *fHashLink;
|
||||||
tcp_state fState;
|
tcp_state fState;
|
||||||
|
status_t fError;
|
||||||
benaphore fLock;
|
benaphore fLock;
|
||||||
|
net_timer fTimer;
|
||||||
|
|
||||||
net_route *fRoute;
|
net_route *fRoute;
|
||||||
};
|
};
|
||||||
@@ -105,16 +115,18 @@ TCPConnection::TCPSegment::~TCPSegment()
|
|||||||
TCPConnection::TCPConnection(net_socket *socket)
|
TCPConnection::TCPConnection(net_socket *socket)
|
||||||
:
|
:
|
||||||
fLastByteAckd(0), //system_time()),
|
fLastByteAckd(0), //system_time()),
|
||||||
fNextByteToSend(0), //fLastByteAckd),
|
fNextByteToSend(fLastByteAckd), //fLastByteAckd),
|
||||||
fLastByteWritten(0), //fLastByteAckd),
|
fNextByteToWrite(fLastByteAckd + 1), //fLastByteAckd),
|
||||||
fLastByteRead(0),
|
fNextByteToRead(0),
|
||||||
fNextByteExpected(0),
|
fNextByteExpected(0),
|
||||||
fLastByteReceived(0),
|
fLastByteReceived(0),
|
||||||
fAvgRTT(TCP_INITIAL_RTT),
|
fAvgRTT(TCP_INITIAL_RTT),
|
||||||
fState(CLOSED),
|
fState(CLOSED),
|
||||||
|
fError(B_OK),
|
||||||
fRoute(NULL)
|
fRoute(NULL)
|
||||||
{
|
{
|
||||||
benaphore_init(&fLock, "TCPConnection");
|
benaphore_init(&fLock, "TCPConnection");
|
||||||
|
sStackModule->init_timer(&fTimer, TimeWait, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -130,7 +142,7 @@ TCPConnection::Open()
|
|||||||
TRACE(("%p.Open()\n", this));
|
TRACE(("%p.Open()\n", this));
|
||||||
if (sAddressModule == NULL)
|
if (sAddressModule == NULL)
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
TRACE(("Using Address Module %p\n", sAddressModule));
|
TRACE(("TCP: Open(): Using Address Module %p\n", sAddressModule));
|
||||||
|
|
||||||
BenaphoreLocker lock(&fLock);
|
BenaphoreLocker lock(&fLock);
|
||||||
sAddressModule->set_to_empty_address((sockaddr *)&socket->address);
|
sAddressModule->set_to_empty_address((sockaddr *)&socket->address);
|
||||||
@@ -144,7 +156,31 @@ TCPConnection::Open()
|
|||||||
status_t
|
status_t
|
||||||
TCPConnection::Close()
|
TCPConnection::Close()
|
||||||
{
|
{
|
||||||
TRACE(("%p.Close()\n", this));
|
BenaphoreLocker lock(&fLock);
|
||||||
|
TRACE(("TCP:%p.Close()\n", this));
|
||||||
|
if (fState == SYN_SENT || fState == LISTEN) {
|
||||||
|
fState = CLOSED;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
tcp_state nextState = CLOSED;
|
||||||
|
if (fState == SYN_RCVD || fState == ESTABLISHED)
|
||||||
|
nextState = FIN_WAIT1;
|
||||||
|
if (fState == CLOSE_WAIT)
|
||||||
|
nextState = LAST_ACK;
|
||||||
|
status_t status = Send(TCP_FLG_FIN | TCP_FLG_ACK, false);
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
fState = nextState;
|
||||||
|
TRACE(("TCP: %p.Close(): Entering state %d\n", this, fState));
|
||||||
|
// need to wait until fState returns to CLOSED
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
TCPConnection::Free()
|
||||||
|
{
|
||||||
|
TRACE(("TCP:%p.Free()\n", this));
|
||||||
|
|
||||||
BenaphoreLocker hashLock(&sTCPLock);
|
BenaphoreLocker hashLock(&sTCPLock);
|
||||||
BenaphoreLocker lock(&fLock);
|
BenaphoreLocker lock(&fLock);
|
||||||
@@ -157,14 +193,6 @@ TCPConnection::Close()
|
|||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
|
||||||
TCPConnection::Free()
|
|
||||||
{
|
|
||||||
TRACE(("%p.Free()\n", this));
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Creates and sends a SYN packet to /a address
|
Creates and sends a SYN packet to /a address
|
||||||
*/
|
*/
|
||||||
@@ -222,6 +250,9 @@ TCPConnection::Connect(const struct sockaddr *address)
|
|||||||
if (sAddressModule->is_empty_address((sockaddr *)&socket->address, false)) {
|
if (sAddressModule->is_empty_address((sockaddr *)&socket->address, false)) {
|
||||||
TRACE(("TCP: Connect(): Local Address is INADDR_ANY\n"));
|
TRACE(("TCP: Connect(): Local Address is INADDR_ANY\n"));
|
||||||
sAddressModule->set_to((sockaddr *)&socket->address, (sockaddr *)fRoute->interface->address);
|
sAddressModule->set_to((sockaddr *)&socket->address, (sockaddr *)fRoute->interface->address);
|
||||||
|
// since most stacks terminate connections from port 0
|
||||||
|
// use port 40000 for now. This should be moved to Bind().
|
||||||
|
sAddressModule->set_port((sockaddr *)&socket->address, htons(40000));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -238,7 +269,7 @@ TCPConnection::Connect(const struct sockaddr *address)
|
|||||||
|
|
||||||
TRACE(("TCP: Connect(): starting 3-way handshake...\n"));
|
TRACE(("TCP: Connect(): starting 3-way handshake...\n"));
|
||||||
// send SYN
|
// send SYN
|
||||||
status = Send(TCP_FLG_SYN);
|
status = Send(TCP_FLG_SYN, false);
|
||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
return status;
|
return status;
|
||||||
fState = SYN_SENT;
|
fState = SYN_SENT;
|
||||||
@@ -252,7 +283,7 @@ TCPConnection::Connect(const struct sockaddr *address)
|
|||||||
status_t
|
status_t
|
||||||
TCPConnection::Accept(struct net_socket **_acceptedSocket)
|
TCPConnection::Accept(struct net_socket **_acceptedSocket)
|
||||||
{
|
{
|
||||||
TRACE(("%p.Accept()\n", this));
|
TRACE(("TCP:%p.Accept()\n", this));
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,7 +345,7 @@ TCPConnection::Unbind(struct sockaddr *address)
|
|||||||
status_t
|
status_t
|
||||||
TCPConnection::Listen(int count)
|
TCPConnection::Listen(int count)
|
||||||
{
|
{
|
||||||
TRACE(("%p.Listen()\n", this));
|
TRACE(("TCP:%p.Listen()\n", this));
|
||||||
if (fState != CLOSED)
|
if (fState != CLOSED)
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
fState = LISTEN;
|
fState = LISTEN;
|
||||||
@@ -325,7 +356,7 @@ TCPConnection::Listen(int count)
|
|||||||
status_t
|
status_t
|
||||||
TCPConnection::Shutdown(int direction)
|
TCPConnection::Shutdown(int direction)
|
||||||
{
|
{
|
||||||
TRACE(("%p.Shutdown()\n", this));
|
TRACE(("TCP:%p.Shutdown()\n", this));
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -336,7 +367,7 @@ TCPConnection::Shutdown(int direction)
|
|||||||
status_t
|
status_t
|
||||||
TCPConnection::SendData(net_buffer *buffer)
|
TCPConnection::SendData(net_buffer *buffer)
|
||||||
{
|
{
|
||||||
TRACE(("%p.SendData()\n", this));
|
TRACE(("TCP:%p.SendData()\n", this));
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -344,7 +375,7 @@ TCPConnection::SendData(net_buffer *buffer)
|
|||||||
status_t
|
status_t
|
||||||
TCPConnection::SendRoutedData(net_route *route, net_buffer *buffer)
|
TCPConnection::SendRoutedData(net_route *route, net_buffer *buffer)
|
||||||
{
|
{
|
||||||
TRACE(("%p.SendRoutedData()\n", this));
|
TRACE(("TCP:%p.SendRoutedData()\n", this));
|
||||||
fRoute = route;
|
fRoute = route;
|
||||||
return SendData(buffer);
|
return SendData(buffer);
|
||||||
}
|
}
|
||||||
@@ -353,7 +384,7 @@ TCPConnection::SendRoutedData(net_route *route, net_buffer *buffer)
|
|||||||
status_t
|
status_t
|
||||||
TCPConnection::SendAvailable()
|
TCPConnection::SendAvailable()
|
||||||
{
|
{
|
||||||
TRACE(("%p.SendAvailable()\n", this));
|
TRACE(("TCP:%p.SendAvailable()\n", this));
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -361,7 +392,7 @@ TCPConnection::SendAvailable()
|
|||||||
status_t
|
status_t
|
||||||
TCPConnection::ReadData(size_t numBytes, uint32 flags, net_buffer **_buffer)
|
TCPConnection::ReadData(size_t numBytes, uint32 flags, net_buffer **_buffer)
|
||||||
{
|
{
|
||||||
TRACE(("%p.ReadData()\n", this));
|
TRACE(("TCP:%p.ReadData()\n", this));
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -369,7 +400,7 @@ TCPConnection::ReadData(size_t numBytes, uint32 flags, net_buffer **_buffer)
|
|||||||
status_t
|
status_t
|
||||||
TCPConnection::ReadAvailable()
|
TCPConnection::ReadAvailable()
|
||||||
{
|
{
|
||||||
TRACE(("%p.ReadAvailable()\n", this));
|
TRACE(("TCP:%p.ReadAvailable()\n", this));
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -378,21 +409,27 @@ status_t
|
|||||||
TCPConnection::ReceiveData(net_buffer *buffer)
|
TCPConnection::ReceiveData(net_buffer *buffer)
|
||||||
{
|
{
|
||||||
BenaphoreLocker lock(&fLock);
|
BenaphoreLocker lock(&fLock);
|
||||||
TRACE(("%p.ReceiveData()\n", this));
|
TRACE(("TCP:%p.ReceiveData()\n", this));
|
||||||
|
|
||||||
NetBufferHeader<tcp_header> bufferHeader(buffer);
|
NetBufferHeader<tcp_header> bufferHeader(buffer);
|
||||||
if (bufferHeader.Status() < B_OK)
|
if (bufferHeader.Status() < B_OK)
|
||||||
return bufferHeader.Status();
|
return bufferHeader.Status();
|
||||||
|
|
||||||
tcp_header &header = bufferHeader.Data();
|
tcp_header &header = bufferHeader.Data();
|
||||||
uint16 flags = 0x0;
|
|
||||||
status_t status;
|
|
||||||
|
|
||||||
|
uint16 flags = 0x0;
|
||||||
|
tcp_state nextState = fState;
|
||||||
|
status_t status = B_OK;
|
||||||
|
uint32 byteAckd = ntohl(header.acknowledge_num);
|
||||||
|
uint32 byteRcvd = ntohl(header.sequence_num);
|
||||||
|
uint32 payloadLength = buffer->size - ((uint32)header.header_length << 2);
|
||||||
|
|
||||||
|
TRACE(("TCP: Receive(): Connection in state %d received packet %p with flags %X!\n", fState, buffer, header.flags));
|
||||||
switch (fState) {
|
switch (fState) {
|
||||||
case CLOSED:
|
case CLOSED:
|
||||||
|
case TIME_WAIT:
|
||||||
// shouldn't happen. send RST
|
// shouldn't happen. send RST
|
||||||
TRACE(("TCP: Connection in CLOSED state received packet %p!\n", buffer));
|
Reset(byteRcvd + payloadLength, 0);
|
||||||
Send(TCP_FLG_RST);
|
|
||||||
break;
|
break;
|
||||||
case LISTEN:
|
case LISTEN:
|
||||||
// if packet is SYN, spawn new TCPConnection in SYN_RCVD state
|
// if packet is SYN, spawn new TCPConnection in SYN_RCVD state
|
||||||
@@ -404,38 +441,127 @@ TCPConnection::ReceiveData(net_buffer *buffer)
|
|||||||
// The current TCPConnection always remains in LISTEN state.
|
// The current TCPConnection always remains in LISTEN state.
|
||||||
break;
|
break;
|
||||||
case SYN_SENT:
|
case SYN_SENT:
|
||||||
TRACE(("TCP: Connection in SYN_SENT state received packet %p!\n", buffer));
|
case SYN_RCVD:
|
||||||
// if packet is SYN+ACK, send ACK & enter ESTABLISHED state.
|
// if packet is SYN+ACK, send ACK & enter ESTABLISHED state.
|
||||||
// if packet is SYN, send ACK & enter SYN_RCVD state.
|
// if packet is SYN, send ACK & enter SYN_RCVD state.
|
||||||
if (header.flags & TCP_FLG_SYN) {
|
if (header.flags & TCP_FLG_RST) {
|
||||||
fNextByteExpected = ntohl(header.sequence_num) + 1;
|
fError = ECONNREFUSED;
|
||||||
flags |= TCP_FLG_ACK;
|
fState = CLOSED;
|
||||||
if (header.flags & TCP_FLG_ACK) {
|
return B_ERROR;
|
||||||
fState = ESTABLISHED;
|
}
|
||||||
} else {
|
if (TCP_IS_GOOD_ACK(byteAckd)) {
|
||||||
flags |= TCP_FLG_SYN;
|
if (header.flags & TCP_FLG_SYN) {
|
||||||
fState = SYN_RCVD;
|
fNextByteToRead =
|
||||||
|
fNextByteExpected =
|
||||||
|
fLastByteReceived = ntohl(header.sequence_num) + 1;
|
||||||
|
flags |= TCP_FLG_ACK;
|
||||||
|
if (header.flags & TCP_FLG_ACK) {
|
||||||
|
fLastByteAckd = byteAckd;
|
||||||
|
// cancel resend of this segment
|
||||||
|
nextState = ESTABLISHED;
|
||||||
|
} else {
|
||||||
|
flags |= TCP_FLG_SYN;
|
||||||
|
nextState = SYN_RCVD;
|
||||||
|
}
|
||||||
|
status = Send(flags, false);
|
||||||
|
if (status == B_OK)
|
||||||
|
fState = nextState;
|
||||||
}
|
}
|
||||||
status = Send(flags);
|
} else {
|
||||||
if (status != B_OK)
|
Reset(byteRcvd + payloadLength, 0);
|
||||||
fState = SYN_SENT;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SYN_RCVD:
|
|
||||||
// if packet is ACK, enter ESTABLISHED
|
|
||||||
if (header.flags & TCP_FLG_ACK)
|
|
||||||
fState = ESTABLISHED;
|
|
||||||
break;
|
|
||||||
case ESTABLISHED:
|
|
||||||
// if packet has ACK, update send buffer
|
|
||||||
// if packet is FIN, send ACK & enter CLOSE_WAIT
|
|
||||||
// update receive buffer if necessary
|
|
||||||
break;
|
|
||||||
// more cases needed covering connection tear-down
|
|
||||||
default:
|
default:
|
||||||
return B_ERROR;
|
// In a synchronized state.
|
||||||
|
// first check that the received sequence number is good
|
||||||
|
if (TCP_IS_GOOD_SEQ(byteRcvd, payloadLength)) {
|
||||||
|
// If a valid RST was received, terminate the connection.
|
||||||
|
if (header.flags & TCP_FLG_RST) {
|
||||||
|
fError = ECONNREFUSED;
|
||||||
|
fState = CLOSED;
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
if (header.flags & TCP_FLG_ACK && TCP_IS_GOOD_ACK(byteAckd) ) {
|
||||||
|
fLastByteAckd = byteAckd;
|
||||||
|
if (fLastByteAckd == fNextByteToWrite) {
|
||||||
|
if (fState == LAST_ACK ) {
|
||||||
|
nextState = CLOSED;
|
||||||
|
status = hash_remove(sTCPHash, this);
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
if (fState == CLOSING) {
|
||||||
|
nextState = TIME_WAIT;
|
||||||
|
status = hash_remove(sTCPHash, this);
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
if (fState == FIN_WAIT1) {
|
||||||
|
nextState = FIN_WAIT2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (header.flags & TCP_FLG_FIN) {
|
||||||
|
// other side is closing connection. change states
|
||||||
|
switch (fState) {
|
||||||
|
case ESTABLISHED:
|
||||||
|
nextState = CLOSE_WAIT;
|
||||||
|
fNextByteExpected++;
|
||||||
|
break;
|
||||||
|
case FIN_WAIT2:
|
||||||
|
nextState = TIME_WAIT;
|
||||||
|
fNextByteExpected++;
|
||||||
|
break;
|
||||||
|
case FIN_WAIT1:
|
||||||
|
if (fLastByteAckd == fNextByteToWrite) {
|
||||||
|
// our FIN has been ACKd: go to TIME_WAIT
|
||||||
|
nextState = TIME_WAIT;
|
||||||
|
status = hash_remove(sTCPHash, this);
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
sStackModule->set_timer(&fTimer, TCP_MAX_SEGMENT_LIFETIME);
|
||||||
|
} else
|
||||||
|
nextState = CLOSING;
|
||||||
|
fNextByteExpected++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fState != CLOSING && fState != LAST_ACK)
|
||||||
|
status = Send(flags | TCP_FLG_ACK, false);
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
fState = nextState;
|
||||||
|
} else {
|
||||||
|
// out-of-order packet received. remind the other side of where we are
|
||||||
|
return Send(TCP_FLG_ACK, true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return B_ERROR;
|
TRACE(("TCP %p.Receive():Entering state %d\n", this, fState));
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
TCPConnection::Reset(uint32 sequenceNum, uint32 acknowledgeNum)
|
||||||
|
{
|
||||||
|
TRACE(("TCP:%p.Reset()\n", this));
|
||||||
|
net_buffer *reply_buf = sBufferModule->create(512);
|
||||||
|
sAddressModule->set_to((sockaddr *)&reply_buf->source, (sockaddr *)&socket->address);
|
||||||
|
sAddressModule->set_to((sockaddr *)&reply_buf->destination, (sockaddr *)&socket->peer);
|
||||||
|
|
||||||
|
status_t status = tcp_segment(reply_buf, TCP_FLG_RST , sequenceNum, acknowledgeNum, 0);
|
||||||
|
if (status != B_OK) {
|
||||||
|
sBufferModule->free(reply_buf);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
TRACE(("TCP: Reset():Sending RST...\n"));
|
||||||
|
status = next->module->send_routed_data(next, fRoute, reply_buf);
|
||||||
|
if (status !=B_OK)
|
||||||
|
sBufferModule->free(reply_buf);
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -446,7 +572,7 @@ TCPConnection::ReceiveData(net_buffer *buffer)
|
|||||||
void
|
void
|
||||||
TCPConnection::ResendSegment(struct net_timer *timer, void *data)
|
TCPConnection::ResendSegment(struct net_timer *timer, void *data)
|
||||||
{
|
{
|
||||||
TRACE(("ResendSegment(%p)\n", data));
|
TRACE(("TCP:ResendSegment(%p)\n", data));
|
||||||
if (data == NULL)
|
if (data == NULL)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -454,17 +580,17 @@ TCPConnection::ResendSegment(struct net_timer *timer, void *data)
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sends a TCP packet with the specified \a flags. If there is any data in
|
Sends a TCP packet with the specified \a flags. If there is any data in
|
||||||
the send buffer, fEffectiveWindow bytes or less of it are sent as well.
|
the send buffer and \a empty is false, fEffectiveWindow bytes or less of it are sent as well.
|
||||||
Sequence and Acknowledgement numbers are filled in accordingly.
|
Sequence and Acknowledgement numbers are filled in accordingly.
|
||||||
The fLock benaphore must be held before calling.
|
The fLock benaphore must be held before calling.
|
||||||
*/
|
*/
|
||||||
status_t
|
status_t
|
||||||
TCPConnection::Send(uint16 flags)
|
TCPConnection::Send(uint16 flags, bool empty)
|
||||||
{
|
{
|
||||||
TRACE(("%p.Send()\n", this));
|
TRACE(("TCP:%p.Send(%X,%s)\n", this, flags, empty ? "1" : "0"));
|
||||||
|
|
||||||
net_buffer *buffer;
|
net_buffer *buffer;
|
||||||
if (1/*no data in send buffer*/) {
|
if (1/*no data in send buffer*/ || empty) {
|
||||||
buffer = sBufferModule->create(512);
|
buffer = sBufferModule->create(512);
|
||||||
TRACE(("TCP: Sending Buffer %p\n", buffer));
|
TRACE(("TCP: Sending Buffer %p\n", buffer));
|
||||||
if (buffer == NULL)
|
if (buffer == NULL)
|
||||||
@@ -480,7 +606,7 @@ TCPConnection::Send(uint16 flags)
|
|||||||
TRACE(("TCP:%p.Send() from address %s\n", this,
|
TRACE(("TCP:%p.Send() from address %s\n", this,
|
||||||
AddressString(sDomain, (sockaddr *)&buffer->source, true).Data()));
|
AddressString(sDomain, (sockaddr *)&buffer->source, true).Data()));
|
||||||
|
|
||||||
uint16 advWin = TCP_MAX_RECV_BUF - (fNextByteExpected - fLastByteRead);
|
uint16 advWin = TCP_MAX_RECV_BUF - (fNextByteExpected - fNextByteToRead);
|
||||||
uint32 size = buffer->size;
|
uint32 size = buffer->size;
|
||||||
|
|
||||||
status_t status = tcp_segment(buffer, flags, fNextByteToSend, fNextByteExpected, advWin);
|
status_t status = tcp_segment(buffer, flags, fNextByteToSend, fNextByteExpected, advWin);
|
||||||
@@ -488,11 +614,13 @@ TCPConnection::Send(uint16 flags)
|
|||||||
sBufferModule->free(buffer);
|
sBufferModule->free(buffer);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
// Only count 1 SYN, the 1 sent when transitioning from CLOSED or LISTEN
|
||||||
|
if (TCP_FLG_SYN & flags && (fState == CLOSED || fState == LISTEN))
|
||||||
|
fNextByteToSend++;
|
||||||
|
// Only count 1 FIN, the 1 sent when transitioning from ESTABLISHED, SYN_RCVD or CLOSE_WAIT
|
||||||
|
if (TCP_FLG_FIN & flags && (fState == SYN_RCVD || fState == ESTABLISHED || fState == CLOSE_WAIT))
|
||||||
|
fNextByteToSend++;
|
||||||
fNextByteToSend += size;
|
fNextByteToSend += size;
|
||||||
if (TCP_FLG_SYN & flags)
|
|
||||||
fNextByteToSend++;
|
|
||||||
if (TCP_FLG_FIN & flags)
|
|
||||||
fNextByteToSend++;
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
TCPSegment *segment = new(std::nothrow)
|
TCPSegment *segment = new(std::nothrow)
|
||||||
@@ -503,6 +631,12 @@ TCPConnection::Send(uint16 flags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TCPConnection::TimeWait(struct net_timer *timer, void *data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
TCPConnection::Compare(void *_connection, const void *_key)
|
TCPConnection::Compare(void *_connection, const void *_key)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -356,7 +356,6 @@ tcp_receive_data(net_buffer *buffer)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sBufferModule->free(buffer);
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,15 +40,14 @@ struct tcp_header {
|
|||||||
uint16 advertised_window;
|
uint16 advertised_window;
|
||||||
uint16 checksum;
|
uint16 checksum;
|
||||||
uint16 urgent_ptr;
|
uint16 urgent_ptr;
|
||||||
uint32 options;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* TCP flag constants */
|
// TCP flag constants
|
||||||
#define TCP_FLG_CWR 0x80 /* Congestion Window Reduced */
|
#define TCP_FLG_CWR 0x80 // Congestion Window Reduced
|
||||||
#define TCP_FLG_ECN 0x40 /* Explicit Congestion Notification echo */
|
#define TCP_FLG_ECN 0x40 // Explicit Congestion Notification echo
|
||||||
#define TCP_FLG_URG 0x20 /* URGent */
|
#define TCP_FLG_URG 0x20 // URGent
|
||||||
#define TCP_FLG_ACK 0x10 /* ACKnowledge */
|
#define TCP_FLG_ACK 0x10 // ACKnowledge
|
||||||
#define TCP_FLG_PUS 0x08 /* PUSh */
|
#define TCP_FLG_PUS 0x08 // PUSh
|
||||||
#define TCP_FLG_RST 0x04 /* ReSeT */
|
#define TCP_FLG_RST 0x04 // ReSeT
|
||||||
#define TCP_FLG_SYN 0x02 /* SYNchronize */
|
#define TCP_FLG_SYN 0x02 // SYNchronize
|
||||||
#define TCP_FLG_FIN 0x01 /* FINish */
|
#define TCP_FLG_FIN 0x01 // FINish
|
||||||
|
|||||||
Reference in New Issue
Block a user