Three way handshake is now functional. Need to add error conditions and graceful cleanup.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18682 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -10,7 +10,7 @@
|
|||||||
#define TCP_INITIAL_RTT 120000000LL
|
#define TCP_INITIAL_RTT 120000000LL
|
||||||
|
|
||||||
// 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 1024
|
#define TCP_MAX_SEND_BUF 0//1024
|
||||||
#define TCP_MAX_RECV_BUF TCP_MAX_SEND_BUF
|
#define TCP_MAX_RECV_BUF TCP_MAX_SEND_BUF
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -59,10 +59,10 @@ private:
|
|||||||
bool fTimedOut;
|
bool fTimedOut;
|
||||||
};
|
};
|
||||||
|
|
||||||
status_t Send(uint8 flags);
|
status_t Send(uint16 flags);
|
||||||
|
|
||||||
uint32 fLastByteSent;
|
|
||||||
uint32 fLastByteAckd;
|
uint32 fLastByteAckd;
|
||||||
|
uint32 fNextByteToSend;
|
||||||
uint32 fLastByteWritten;
|
uint32 fLastByteWritten;
|
||||||
|
|
||||||
uint32 fLastByteRead;
|
uint32 fLastByteRead;
|
||||||
@@ -104,9 +104,12 @@ TCPConnection::TCPSegment::~TCPSegment()
|
|||||||
|
|
||||||
TCPConnection::TCPConnection(net_socket *socket)
|
TCPConnection::TCPConnection(net_socket *socket)
|
||||||
:
|
:
|
||||||
fLastByteSent(0), //system_time()),
|
fLastByteAckd(0), //system_time()),
|
||||||
fLastByteAckd(1), //fLastByteSent + 1),
|
fNextByteToSend(0), //fLastByteAckd),
|
||||||
fLastByteWritten(1), //fLastByteSent + 1),
|
fLastByteWritten(0), //fLastByteAckd),
|
||||||
|
fLastByteRead(0),
|
||||||
|
fNextByteExpected(0),
|
||||||
|
fLastByteReceived(0),
|
||||||
fAvgRTT(TCP_INITIAL_RTT),
|
fAvgRTT(TCP_INITIAL_RTT),
|
||||||
fState(CLOSED),
|
fState(CLOSED),
|
||||||
fRoute(NULL)
|
fRoute(NULL)
|
||||||
@@ -201,12 +204,27 @@ TCPConnection::Connect(const struct sockaddr *address)
|
|||||||
if (hash_lookup(sTCPHash, &key) != NULL) {
|
if (hash_lookup(sTCPHash, &key) != NULL) {
|
||||||
status = hash_remove(sTCPHash, (void *)this);
|
status = hash_remove(sTCPHash, (void *)this);
|
||||||
if (status != B_OK) {
|
if (status != B_OK) {
|
||||||
TRACE(("TCP: Hash Error: %s\n", strerror(status)));
|
TRACE(("TCP: Connect(): Hash Error: %s\n", strerror(status)));
|
||||||
benaphore_unlock(&sTCPLock);
|
benaphore_unlock(&sTCPLock);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
} else
|
} else {
|
||||||
TRACE(("TCP: Connect(): Connection not in hash yet!\n"));
|
TRACE(("TCP: Connect(): Connection not in hash yet!\n"));
|
||||||
|
// get a net_route if there isn't one
|
||||||
|
if (fRoute == NULL) {
|
||||||
|
fRoute = sDatalinkModule->get_route(sDomain, (sockaddr *)address);
|
||||||
|
TRACE(("TCP: Connect(): Using Route %p\n", fRoute));
|
||||||
|
if (fRoute == NULL) {
|
||||||
|
return ENETUNREACH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sAddressModule->is_empty_address((sockaddr *)&socket->address, false)) {
|
||||||
|
TRACE(("TCP: Connect(): Local Address is INADDR_ANY\n"));
|
||||||
|
sAddressModule->set_to((sockaddr *)&socket->address, (sockaddr *)fRoute->interface->address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sAddressModule->set_to((sockaddr *)&socket->peer, address);
|
sAddressModule->set_to((sockaddr *)&socket->peer, address);
|
||||||
status = hash_insert(sTCPHash, (void *)this);
|
status = hash_insert(sTCPHash, (void *)this);
|
||||||
if (status != B_OK) {
|
if (status != B_OK) {
|
||||||
@@ -223,7 +241,7 @@ TCPConnection::Connect(const struct sockaddr *address)
|
|||||||
status = Send(TCP_FLG_SYN);
|
status = Send(TCP_FLG_SYN);
|
||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
return status;
|
return status;
|
||||||
fState=SYN_SENT;
|
fState = SYN_SENT;
|
||||||
|
|
||||||
// TODO: Should Connect() not return until 3-way handshake is complete?
|
// TODO: Should Connect() not return until 3-way handshake is complete?
|
||||||
TRACE(("TCP: Connect(): Connection complete\n"));
|
TRACE(("TCP: Connect(): Connection complete\n"));
|
||||||
@@ -359,12 +377,22 @@ TCPConnection::ReadAvailable()
|
|||||||
status_t
|
status_t
|
||||||
TCPConnection::ReceiveData(net_buffer *buffer)
|
TCPConnection::ReceiveData(net_buffer *buffer)
|
||||||
{
|
{
|
||||||
|
BenaphoreLocker lock(&fLock);
|
||||||
TRACE(("%p.ReceiveData()\n", this));
|
TRACE(("%p.ReceiveData()\n", this));
|
||||||
|
|
||||||
|
NetBufferHeader<tcp_header> bufferHeader(buffer);
|
||||||
|
if (bufferHeader.Status() < B_OK)
|
||||||
|
return bufferHeader.Status();
|
||||||
|
|
||||||
|
tcp_header &header = bufferHeader.Data();
|
||||||
|
uint16 flags = 0x0;
|
||||||
|
status_t status;
|
||||||
|
|
||||||
switch (fState) {
|
switch (fState) {
|
||||||
case CLOSED:
|
case CLOSED:
|
||||||
// shouldn't happen. send RST
|
// shouldn't happen. send RST
|
||||||
TRACE(("TCP: Connection in CLOSED state received packet %p!\n", buffer));
|
TRACE(("TCP: Connection in CLOSED state received packet %p!\n", buffer));
|
||||||
|
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
|
||||||
@@ -376,11 +404,27 @@ 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));
|
||||||
// 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) {
|
||||||
|
fNextByteExpected = ntohl(header.sequence_num) + 1;
|
||||||
|
flags |= TCP_FLG_ACK;
|
||||||
|
if (header.flags & TCP_FLG_ACK) {
|
||||||
|
fState = ESTABLISHED;
|
||||||
|
} else {
|
||||||
|
flags |= TCP_FLG_SYN;
|
||||||
|
fState = SYN_RCVD;
|
||||||
|
}
|
||||||
|
status = Send(flags);
|
||||||
|
if (status != B_OK)
|
||||||
|
fState = SYN_SENT;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case SYN_RCVD:
|
case SYN_RCVD:
|
||||||
// if packet is ACK, enter ESTABLISHED
|
// if packet is ACK, enter ESTABLISHED
|
||||||
|
if (header.flags & TCP_FLG_ACK)
|
||||||
|
fState = ESTABLISHED;
|
||||||
break;
|
break;
|
||||||
case ESTABLISHED:
|
case ESTABLISHED:
|
||||||
// if packet has ACK, update send buffer
|
// if packet has ACK, update send buffer
|
||||||
@@ -415,34 +459,40 @@ TCPConnection::ResendSegment(struct net_timer *timer, void *data)
|
|||||||
The fLock benaphore must be held before calling.
|
The fLock benaphore must be held before calling.
|
||||||
*/
|
*/
|
||||||
status_t
|
status_t
|
||||||
TCPConnection::Send(uint8 flags)
|
TCPConnection::Send(uint16 flags)
|
||||||
{
|
{
|
||||||
TRACE(("%p.Send()\n", this));
|
TRACE(("%p.Send()\n", this));
|
||||||
return B_OK;
|
|
||||||
|
|
||||||
uint32 sequenceNum = 0;
|
|
||||||
uint32 ackNum = 0;
|
|
||||||
net_buffer *buffer;
|
net_buffer *buffer;
|
||||||
if (1/*no data in send buffer*/) {
|
if (1/*no data in send buffer*/) {
|
||||||
buffer = sBufferModule->create(512);
|
buffer = sBufferModule->create(512);
|
||||||
|
TRACE(("TCP: Sending Buffer %p\n", buffer));
|
||||||
if (buffer == NULL)
|
if (buffer == NULL)
|
||||||
return ENOBUFS;
|
return ENOBUFS;
|
||||||
} else {
|
} else {
|
||||||
//TODO: create net_buffer from data in send buffer
|
//TODO: create net_buffer from data in send buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
// get a net_route if there isn't one
|
sAddressModule->set_to((sockaddr *)&buffer->source, (sockaddr *)&socket->address);
|
||||||
if (fRoute == NULL) {
|
sAddressModule->set_to((sockaddr *)&buffer->destination, (sockaddr *)&socket->peer);
|
||||||
fRoute = sDatalinkModule->get_route(sDomain, (sockaddr *)&socket->peer);
|
TRACE(("TCP:%p.Send() to address %s\n", this,
|
||||||
if (fRoute == NULL) {
|
AddressString(sDomain, (sockaddr *)&buffer->destination, true).Data()));
|
||||||
sBufferModule->free(buffer);
|
TRACE(("TCP:%p.Send() from address %s\n", this,
|
||||||
return ENETUNREACH;
|
AddressString(sDomain, (sockaddr *)&buffer->source, true).Data()));
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16 advWin = TCP_MAX_RECV_BUF - (fNextByteExpected - fLastByteRead);
|
uint16 advWin = TCP_MAX_RECV_BUF - (fNextByteExpected - fLastByteRead);
|
||||||
|
uint32 size = buffer->size;
|
||||||
|
|
||||||
tcp_segment(buffer, flags, sequenceNum, ackNum, advWin);
|
status_t status = tcp_segment(buffer, flags, fNextByteToSend, fNextByteExpected, advWin);
|
||||||
|
if (status != B_OK) {
|
||||||
|
sBufferModule->free(buffer);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
|||||||
@@ -259,7 +259,7 @@ tcp_segment(net_buffer *buffer, uint16 flags, uint32 seq, uint32 ack, uint16 adv
|
|||||||
header.reserved = 0;
|
header.reserved = 0;
|
||||||
header.header_length = 5;// currently no options supported
|
header.header_length = 5;// currently no options supported
|
||||||
header.flags = (uint8)flags;
|
header.flags = (uint8)flags;
|
||||||
header.advertised_window = adv_win;
|
header.advertised_window = htons(adv_win);
|
||||||
header.checksum = 0;
|
header.checksum = 0;
|
||||||
header.urgent_ptr = 0;// urgent pointer not supported
|
header.urgent_ptr = 0;// urgent pointer not supported
|
||||||
|
|
||||||
@@ -272,7 +272,7 @@ tcp_segment(net_buffer *buffer, uint16 flags, uint32 seq, uint32 ack, uint16 adv
|
|||||||
<< (uint16)htons(buffer->size)
|
<< (uint16)htons(buffer->size)
|
||||||
<< Checksum::BufferHelper(buffer, sBufferModule);
|
<< Checksum::BufferHelper(buffer, sBufferModule);
|
||||||
header.checksum = checksum;
|
header.checksum = checksum;
|
||||||
TRACE(("TCP: Checksum for segment %p is %d\n", buffer, header.checksum));
|
TRACE(("TCP: Checksum for segment %p is %X\n", buffer, header.checksum));
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -328,8 +328,8 @@ tcp_receive_data(net_buffer *buffer)
|
|||||||
if (!(header.flags & TCP_FLG_RST)) {
|
if (!(header.flags & TCP_FLG_RST)) {
|
||||||
TRACE(("TCP: Connection does not exist!\n"));
|
TRACE(("TCP: Connection does not exist!\n"));
|
||||||
net_buffer *reply_buf = sBufferModule->create(512);
|
net_buffer *reply_buf = sBufferModule->create(512);
|
||||||
reply_buf->source = buffer->destination;
|
sAddressModule->set_to((sockaddr *)&reply_buf->source, (sockaddr *)&buffer->destination);
|
||||||
reply_buf->destination = buffer->source;
|
sAddressModule->set_to((sockaddr *)&reply_buf->destination, (sockaddr *)&buffer->source);
|
||||||
|
|
||||||
uint32 sequenceNum, acknowledgeNum;
|
uint32 sequenceNum, acknowledgeNum;
|
||||||
uint16 flags;
|
uint16 flags;
|
||||||
@@ -354,7 +354,6 @@ tcp_receive_data(net_buffer *buffer)
|
|||||||
sBufferModule->free(reply_buf);
|
sBufferModule->free(reply_buf);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
TRACE(("TCP: Sent.\n"));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sBufferModule->free(buffer);
|
sBufferModule->free(buffer);
|
||||||
|
|||||||
Reference in New Issue
Block a user