From 806e2ef627cbcf37cc7e2ab394c351a398b300df Mon Sep 17 00:00:00 2001 From: Andrew Galante Date: Tue, 29 Aug 2006 00:52:52 +0000 Subject: [PATCH] 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 --- .../network/protocols/tcp/TCPConnection.h | 94 ++++++++++++++----- .../kernel/network/protocols/tcp/tcp.cpp | 9 +- 2 files changed, 76 insertions(+), 27 deletions(-) diff --git a/src/add-ons/kernel/network/protocols/tcp/TCPConnection.h b/src/add-ons/kernel/network/protocols/tcp/TCPConnection.h index 44a2cd9b53..40f8cb57f5 100644 --- a/src/add-ons/kernel/network/protocols/tcp/TCPConnection.h +++ b/src/add-ons/kernel/network/protocols/tcp/TCPConnection.h @@ -10,7 +10,7 @@ #define TCP_INITIAL_RTT 120000000LL // 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 typedef struct { @@ -59,10 +59,10 @@ private: bool fTimedOut; }; - status_t Send(uint8 flags); + status_t Send(uint16 flags); - uint32 fLastByteSent; uint32 fLastByteAckd; + uint32 fNextByteToSend; uint32 fLastByteWritten; uint32 fLastByteRead; @@ -104,9 +104,12 @@ TCPConnection::TCPSegment::~TCPSegment() TCPConnection::TCPConnection(net_socket *socket) : - fLastByteSent(0), //system_time()), - fLastByteAckd(1), //fLastByteSent + 1), - fLastByteWritten(1), //fLastByteSent + 1), + fLastByteAckd(0), //system_time()), + fNextByteToSend(0), //fLastByteAckd), + fLastByteWritten(0), //fLastByteAckd), + fLastByteRead(0), + fNextByteExpected(0), + fLastByteReceived(0), fAvgRTT(TCP_INITIAL_RTT), fState(CLOSED), fRoute(NULL) @@ -201,12 +204,27 @@ TCPConnection::Connect(const struct sockaddr *address) if (hash_lookup(sTCPHash, &key) != NULL) { status = hash_remove(sTCPHash, (void *)this); if (status != B_OK) { - TRACE(("TCP: Hash Error: %s\n", strerror(status))); + TRACE(("TCP: Connect(): Hash Error: %s\n", strerror(status))); benaphore_unlock(&sTCPLock); return status; } - } else + } else { 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); status = hash_insert(sTCPHash, (void *)this); if (status != B_OK) { @@ -223,7 +241,7 @@ TCPConnection::Connect(const struct sockaddr *address) status = Send(TCP_FLG_SYN); if (status != B_OK) return status; - fState=SYN_SENT; + fState = SYN_SENT; // TODO: Should Connect() not return until 3-way handshake is complete? TRACE(("TCP: Connect(): Connection complete\n")); @@ -359,12 +377,22 @@ TCPConnection::ReadAvailable() status_t TCPConnection::ReceiveData(net_buffer *buffer) { + BenaphoreLocker lock(&fLock); TRACE(("%p.ReceiveData()\n", this)); + NetBufferHeader bufferHeader(buffer); + if (bufferHeader.Status() < B_OK) + return bufferHeader.Status(); + + tcp_header &header = bufferHeader.Data(); + uint16 flags = 0x0; + status_t status; + switch (fState) { case CLOSED: // shouldn't happen. send RST TRACE(("TCP: Connection in CLOSED state received packet %p!\n", buffer)); + Send(TCP_FLG_RST); break; case LISTEN: // 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. break; 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, 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; 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 @@ -415,34 +459,40 @@ TCPConnection::ResendSegment(struct net_timer *timer, void *data) The fLock benaphore must be held before calling. */ status_t -TCPConnection::Send(uint8 flags) +TCPConnection::Send(uint16 flags) { TRACE(("%p.Send()\n", this)); - return B_OK; - uint32 sequenceNum = 0; - uint32 ackNum = 0; net_buffer *buffer; if (1/*no data in send buffer*/) { buffer = sBufferModule->create(512); + TRACE(("TCP: Sending Buffer %p\n", buffer)); if (buffer == NULL) return ENOBUFS; } else { //TODO: create net_buffer from data in send buffer } - // get a net_route if there isn't one - if (fRoute == NULL) { - fRoute = sDatalinkModule->get_route(sDomain, (sockaddr *)&socket->peer); - if (fRoute == NULL) { - sBufferModule->free(buffer); - return ENETUNREACH; - } - } + sAddressModule->set_to((sockaddr *)&buffer->source, (sockaddr *)&socket->address); + sAddressModule->set_to((sockaddr *)&buffer->destination, (sockaddr *)&socket->peer); + TRACE(("TCP:%p.Send() to address %s\n", this, + AddressString(sDomain, (sockaddr *)&buffer->destination, true).Data())); + TRACE(("TCP:%p.Send() from address %s\n", this, + AddressString(sDomain, (sockaddr *)&buffer->source, true).Data())); 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 TCPSegment *segment = new(std::nothrow) diff --git a/src/add-ons/kernel/network/protocols/tcp/tcp.cpp b/src/add-ons/kernel/network/protocols/tcp/tcp.cpp index c96e308e53..bdbd84196b 100644 --- a/src/add-ons/kernel/network/protocols/tcp/tcp.cpp +++ b/src/add-ons/kernel/network/protocols/tcp/tcp.cpp @@ -259,7 +259,7 @@ tcp_segment(net_buffer *buffer, uint16 flags, uint32 seq, uint32 ack, uint16 adv header.reserved = 0; header.header_length = 5;// currently no options supported header.flags = (uint8)flags; - header.advertised_window = adv_win; + header.advertised_window = htons(adv_win); header.checksum = 0; 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) << Checksum::BufferHelper(buffer, sBufferModule); 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; } @@ -328,8 +328,8 @@ tcp_receive_data(net_buffer *buffer) if (!(header.flags & TCP_FLG_RST)) { TRACE(("TCP: Connection does not exist!\n")); net_buffer *reply_buf = sBufferModule->create(512); - reply_buf->source = buffer->destination; - reply_buf->destination = buffer->source; + sAddressModule->set_to((sockaddr *)&reply_buf->source, (sockaddr *)&buffer->destination); + sAddressModule->set_to((sockaddr *)&reply_buf->destination, (sockaddr *)&buffer->source); uint32 sequenceNum, acknowledgeNum; uint16 flags; @@ -354,7 +354,6 @@ tcp_receive_data(net_buffer *buffer) sBufferModule->free(reply_buf); return status; } - TRACE(("TCP: Sent.\n")); } } sBufferModule->free(buffer);