X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=KernelLand%2FModules%2FIPStack%2Ftcp.c;h=2854f30a0ee853858f05648b85be6e9537e371a1;hb=e14ac96d48bb4ef5cfc845e345df4770e1145ceb;hp=86ff8190e9afa35c29d796b1a5b2345752a23802;hpb=12c9ce3978373fcadb7015e75cce56f6e181488d;p=tpg%2Facess2.git diff --git a/KernelLand/Modules/IPStack/tcp.c b/KernelLand/Modules/IPStack/tcp.c index 86ff8190..2854f30a 100644 --- a/KernelLand/Modules/IPStack/tcp.c +++ b/KernelLand/Modules/IPStack/tcp.c @@ -18,7 +18,7 @@ #define TCP_WINDOW_SIZE 0x2000 #define TCP_RECIEVE_BUFFER_SIZE 0x8000 #define TCP_DACK_THRESHOLD 4096 -#define TCP_DACK_TIMEOUT 500 +#define TCP_DACK_TIMEOUT 100 #define TCP_DEBUG 0 // Set to non-0 to enable TCP packet logging @@ -28,7 +28,9 @@ void TCP_StartConnection(tTCPConnection *Conn); void TCP_SendPacket(tTCPConnection *Conn, tTCPHeader *Header, size_t DataLen, const void *Data); void TCP_int_SendPacket(tInterface *Interface, const void *Dest, tTCPHeader *Header, size_t Length, const void *Data); void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer); -void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Header, int Length); +void TCP_IPError(tInterface *Interface, tIPErrorMode Mode, const void *Address, int Length, const void *Buffer); + int TCP_INT_HandleServerPacket(tInterface *Interface, tTCPListener *Server, const void *Address, tTCPHeader *Header, size_t Length); + int TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Header, int Length); int TCP_INT_AppendRecieved(tTCPConnection *Connection, const void *Data, size_t Length); void TCP_INT_UpdateRecievedFromFuture(tTCPConnection *Connection); void TCP_int_SendDelayedACK(void *ConnPtr); @@ -52,6 +54,7 @@ size_t TCP_Client_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void void TCP_Client_Close(tVFS_Node *Node); // --- Helpers int WrapBetween(Uint32 Lower, Uint32 Value, Uint32 Higher, Uint32 MaxValue); +Uint32 GetRelative(Uint32 Base, Uint32 Value); // === TEMPLATES === tSocketFile gTCP_ServerFile = {NULL, "tcps", TCP_Server_Init}; @@ -65,6 +68,7 @@ tVFS_NodeType gTCP_ServerNodeType = { }; tVFS_NodeType gTCP_ClientNodeType = { .TypeName = "TCP Client/Connection", + .Flags = VFS_NODETYPEFLAG_STREAM, .Read = TCP_Client_Read, .Write = TCP_Client_Write, .IOCtl = TCP_Client_IOCtl, @@ -91,7 +95,7 @@ void TCP_Initialise(void) giTCP_NextOutPort += rand()%128; IPStack_AddFile(&gTCP_ServerFile); IPStack_AddFile(&gTCP_ClientFile); - IPv4_RegisterCallback(IP4PROT_TCP, TCP_GetPacket); + IPv4_RegisterCallback(IP4PROT_TCP, TCP_GetPacket, TCP_IPError); IPv6_RegisterCallback(IP4PROT_TCP, TCP_GetPacket); } @@ -106,61 +110,80 @@ void TCP_SendPacket( tTCPConnection *Conn, tTCPHeader *Header, size_t Length, co TCP_int_SendPacket(Conn->Interface, &Conn->RemoteIP, Header, Length, Data); } -void TCP_int_SendPacket(tInterface *Interface, const void *Dest, tTCPHeader *Header, size_t Length, const void *Data ) +Uint16 TCP_int_CalculateChecksum(int AddrType, const void *LAddr, const void *RAddr, + size_t HeaderLength, const tTCPHeader *Header, size_t DataLength, const void *Data) { - tIPStackBuffer *buffer; + size_t packlen = HeaderLength + DataLength; Uint16 checksum[3]; - int packlen = sizeof(*Header) + Length; - - buffer = IPStack_Buffer_CreateBuffer(2 + IPV4_BUFFERS); - if( Data && Length ) + + switch(AddrType) + { + case 4: { + Uint32 buf[3]; + buf[0] = ((tIPv4*)LAddr)->L; + buf[1] = ((tIPv4*)RAddr)->L; + buf[2] = htonl( (packlen) | (IP4PROT_TCP<<16) | (0<<24) ); + checksum[0] = htons( ~IPv4_Checksum(buf, sizeof(buf)) ); // Partial checksum + break; } + case 6: { + Uint32 buf[4+4+1+1]; + memcpy(&buf[0], LAddr, 16); + memcpy(&buf[4], RAddr, 16); + buf[8] = htonl(packlen); + buf[9] = htonl(IP4PROT_TCP); + checksum[0] = htons( ~IPv4_Checksum(buf, sizeof(buf)) ); // Partial checksum + break; } + default: + return 0; + } + checksum[1] = htons( ~IPv4_Checksum(Header, HeaderLength) ); + checksum[2] = htons( ~IPv4_Checksum(Data, DataLength) ); + + return htons( IPv4_Checksum(checksum, sizeof(checksum)) ); +} + +void TCP_int_SendPacket(tInterface *Interface, const void *Dest, tTCPHeader *Header, size_t Length, const void *Data ) +{ + tIPStackBuffer *buffer = IPStack_Buffer_CreateBuffer(2 + IPV4_BUFFERS); + if( Length > 0 ) IPStack_Buffer_AppendSubBuffer(buffer, Length, 0, Data, NULL, NULL); IPStack_Buffer_AppendSubBuffer(buffer, sizeof(*Header), 0, Header, NULL, NULL); - LOG("Sending %i+%i to %s:%i", sizeof(*Header), Length, + #if TCP_DEBUG + Log_Log("TCP", "TCP_int_SendPacket: :%i to [%s]:%i (%i data), Flags = %s%s%s%s%s%s%s%s", + ntohs(Header->SourcePort), IPStack_PrintAddress(Interface->Type, Dest), - ntohs(Header->RemotePort) + ntohs(Header->DestPort), + Length, + (Header->Flags & TCP_FLAG_CWR) ? "CWR " : "", + (Header->Flags & TCP_FLAG_ECE) ? "ECE " : "", + (Header->Flags & TCP_FLAG_URG) ? "URG " : "", + (Header->Flags & TCP_FLAG_ACK) ? "ACK " : "", + (Header->Flags & TCP_FLAG_PSH) ? "PSH " : "", + (Header->Flags & TCP_FLAG_RST) ? "RST " : "", + (Header->Flags & TCP_FLAG_SYN) ? "SYN " : "", + (Header->Flags & TCP_FLAG_FIN) ? "FIN " : "" ); + #endif Header->Checksum = 0; - checksum[1] = htons( ~IPv4_Checksum(Header, sizeof(tTCPHeader)) ); - checksum[2] = htons( ~IPv4_Checksum(Data, Length) ); + Header->Checksum = TCP_int_CalculateChecksum(Interface->Type, Interface->Address, Dest, + sizeof(tTCPHeader), Header, Length, Data); // TODO: Fragment packet switch( Interface->Type ) { case 4: - // Get IPv4 pseudo-header checksum - { - Uint32 buf[3]; - buf[0] = ((tIPv4*)Interface->Address)->L; - buf[1] = ((tIPv4*)Dest)->L; - buf[2] = htonl( (packlen) | (IP4PROT_TCP<<16) | (0<<24) ); - checksum[0] = htons( ~IPv4_Checksum(buf, sizeof(buf)) ); // Partial checksum - } - // - Combine checksums - Header->Checksum = htons( IPv4_Checksum(checksum, sizeof(checksum)) ); IPv4_SendPacket(Interface, *(tIPv4*)Dest, IP4PROT_TCP, 0, buffer); break; - case 6: - // Append IPv6 Pseudo Header - { - Uint32 buf[4+4+1+1]; - memcpy(buf, Interface->Address, 16); - memcpy(&buf[4], Dest, 16); - buf[8] = htonl(packlen); - buf[9] = htonl(IP4PROT_TCP); - checksum[0] = htons( ~IPv4_Checksum(buf, sizeof(buf)) ); // Partial checksum - } - Header->Checksum = htons( IPv4_Checksum(checksum, sizeof(checksum)) ); // Combine the two IPv6_SendPacket(Interface, *(tIPv6*)Dest, IP4PROT_TCP, buffer); break; } } -void TCP_int_SendRSTTo(tInterface *Interface, void *Address, size_t Length, const tTCPHeader *Header) +void TCP_int_SendRSTTo(tInterface *Interface, const void *Address, size_t Length, const tTCPHeader *Header) { tTCPHeader out_hdr = {0}; @@ -236,95 +259,20 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe { // Check that it is coming in on the same interface if(conn->Interface != Interface) continue; - // Check Source Port - Log_Log("TCP", "TCP_GetPacket: conn->RemotePort(%i) == hdr->SourcePort(%i)", - conn->RemotePort, ntohs(hdr->SourcePort)); if(conn->RemotePort != ntohs(hdr->SourcePort)) continue; - // Check Source IP - Log_Debug("TCP", "TCP_GetPacket: conn->RemoteIP(%s)", - IPStack_PrintAddress(conn->Interface->Type, &conn->RemoteIP)); - Log_Debug("TCP", " == Address(%s)", - IPStack_PrintAddress(conn->Interface->Type, Address)); if( IPStack_CompareAddress(conn->Interface->Type, &conn->RemoteIP, Address, -1) == 0 ) continue ; Log_Log("TCP", "TCP_GetPacket: Matches connection %p", conn); // We have a response! - TCP_INT_HandleConnectionPacket(conn, hdr, Length); - - return; + if( TCP_INT_HandleConnectionPacket(conn, hdr, Length) == 0 ) + return; + break ; } - - if( hdr->Flags & TCP_FLAG_RST ) { - LOG("RST, ignore"); - return ; - } - else if( hdr->Flags & TCP_FLAG_ACK ) { - LOG("ACK, send RST"); - TCP_int_SendRSTTo(Interface, Address, Length, hdr); - return ; - } - else if( !(hdr->Flags & TCP_FLAG_SYN) ) { - LOG("Other, ignore"); - return ; - } - Log_Log("TCP", "TCP_GetPacket: Opening Connection"); - - // TODO: Check for halfopen max - - tTCPConnection *conn = TCP_int_CreateConnection(Interface, TCP_ST_SYN_RCVD); - conn->LocalPort = srv->Port; - conn->RemotePort = ntohs(hdr->SourcePort); - - switch(Interface->Type) - { - case 4: conn->RemoteIP.v4 = *(tIPv4*)Address; break; - case 6: conn->RemoteIP.v6 = *(tIPv6*)Address; break; - default: ASSERTC(Interface->Type,==,4); return; - } - - conn->NextSequenceRcv = ntohl( hdr->SequenceNumber ) + 1; - conn->HighestSequenceRcvd = conn->NextSequenceRcv; - conn->NextSequenceSend = rand(); - - conn->Node.ImplInt = srv->NextID ++; - - // Hmm... Theoretically, this lock will never have to wait, - // as the interface is locked to the watching thread, and this - // runs in the watching thread. But, it's a good idea to have - // it, just in case - // Oh, wait, there is a case where a wildcard can be used - // (srv->Interface == NULL) so having the lock is a good idea - SHORTLOCK(&srv->lConnections); - conn->Server = srv; - conn->Prev = srv->ConnectionsTail; - if(srv->Connections) { - ASSERT(srv->ConnectionsTail); - srv->ConnectionsTail->Next = conn; - } - else { - ASSERT(!srv->ConnectionsTail); - srv->Connections = conn; - } - srv->ConnectionsTail = conn; - if(!srv->NewConnections) - srv->NewConnections = conn; - VFS_MarkAvaliable( &srv->Node, 1 ); - SHORTREL(&srv->lConnections); - Semaphore_Signal(&srv->WaitingConnections, 1); - - // Send the SYN ACK - hdr->Flags |= TCP_FLAG_ACK; - hdr->AcknowlegementNumber = htonl(conn->NextSequenceRcv); - hdr->SequenceNumber = htonl(conn->NextSequenceSend); - hdr->DestPort = hdr->SourcePort; - hdr->SourcePort = htons(srv->Port); - hdr->DataOffset = (sizeof(tTCPHeader)/4) << 4; - TCP_SendPacket( conn, hdr, 0, NULL ); - conn->NextSequenceSend ++; + TCP_INT_HandleServerPacket(Interface, srv, Address, hdr, Length); return ; } @@ -339,13 +287,13 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe if(conn->RemotePort != ntohs(hdr->SourcePort)) continue; // Check Source IP - if(conn->Interface->Type == 6 && !IP6_EQU(conn->RemoteIP.v6, *(tIPv6*)Address)) - continue; - if(conn->Interface->Type == 4 && !IP4_EQU(conn->RemoteIP.v4, *(tIPv4*)Address)) - continue; + if( IPStack_CompareAddress(conn->Interface->Type, &conn->RemoteIP, Address, -1) == 0 ) + continue ; - TCP_INT_HandleConnectionPacket(conn, hdr, Length); - return ; + // Handle or fall through + if( TCP_INT_HandleConnectionPacket(conn, hdr, Length) == 0 ) + return ; + break; } } @@ -357,13 +305,116 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe } } +void TCP_IPError(tInterface *Interface, tIPErrorMode Mode, const void *Address, int Length, const void *Buffer) +{ + if( Length < sizeof(tTCPHeader) ) return ; + + const tTCPHeader *hdr = Buffer; + + // TODO: Handle errors for server connections + + for( tTCPConnection *conn = gTCP_OutbountCons; conn; conn = conn->Next ) + { + if(conn->Interface != Interface) + continue; + if(conn->RemotePort != ntohs(hdr->SourcePort)) + continue; + if( IPStack_CompareAddress(conn->Interface->Type, &conn->RemoteIP, Address, -1) == 0 ) + continue ; + + // Mark an error on the interface + VFS_MarkError(&conn->Node, 1); + return ; + } +} + +/* + * Handle packets in LISTEN state + */ +int TCP_INT_HandleServerPacket(tInterface *Interface, tTCPListener *Server, const void *Address, tTCPHeader *Header, size_t Length) +{ + if( Header->Flags & TCP_FLAG_RST ) { + LOG("RST, ignore"); + return 0; + } + else if( Header->Flags & TCP_FLAG_ACK ) { + LOG("ACK, send RST"); + TCP_int_SendRSTTo(Interface, Address, Length, Header); + return 0; + } + else if( !(Header->Flags & TCP_FLAG_SYN) ) { + LOG("Other, ignore"); + return 0; + } + + Log_Log("TCP", "TCP_GetPacket: Opening Connection"); + + // TODO: Check security (a TCP Option) + // TODO: Check SEG.PRC + // TODO: Check for halfopen max + + tTCPConnection *conn = TCP_int_CreateConnection(Interface, TCP_ST_SYN_RCVD); + conn->LocalPort = Server->Port; + conn->RemotePort = ntohs(Header->SourcePort); + + switch(Interface->Type) + { + case 4: conn->RemoteIP.v4 = *(tIPv4*)Address; break; + case 6: conn->RemoteIP.v6 = *(tIPv6*)Address; break; + default: ASSERTC(Interface->Type,==,4); return 0; + } + + conn->NextSequenceRcv = ntohl( Header->SequenceNumber ) + 1; + conn->HighestSequenceRcvd = conn->NextSequenceRcv; + conn->NextSequenceSend = rand(); + conn->LastACKSequence = ntohl( Header->SequenceNumber ); + + conn->Node.ImplInt = Server->NextID ++; + conn->Node.Size = -1; + + // Hmm... Theoretically, this lock will never have to wait, + // as the interface is locked to the watching thread, and this + // runs in the watching thread. But, it's a good idea to have + // it, just in case + // Oh, wait, there is a case where a wildcard can be used + // (Server->Interface == NULL) so having the lock is a good idea + SHORTLOCK(&Server->lConnections); + conn->Server = Server; + conn->Prev = Server->ConnectionsTail; + if(Server->Connections) { + ASSERT(Server->ConnectionsTail); + Server->ConnectionsTail->Next = conn; + } + else { + ASSERT(!Server->ConnectionsTail); + Server->Connections = conn; + } + Server->ConnectionsTail = conn; + if(!Server->NewConnections) + Server->NewConnections = conn; + VFS_MarkAvaliable( &Server->Node, 1 ); + SHORTREL(&Server->lConnections); + Semaphore_Signal(&Server->WaitingConnections, 1); + + // Send the SYN ACK + Header->Flags = TCP_FLAG_ACK|TCP_FLAG_SYN; + Header->AcknowlegementNumber = htonl(conn->NextSequenceRcv); + Header->SequenceNumber = htonl(conn->NextSequenceSend); + Header->DestPort = Header->SourcePort; + Header->SourcePort = htons(Server->Port); + Header->DataOffset = (sizeof(tTCPHeader)/4) << 4; + TCP_SendPacket( conn, Header, 0, NULL ); + conn->NextSequenceSend ++; + return 0; +} + /** * \brief Handles a packet sent to a specific connection * \param Connection TCP Connection pointer * \param Header TCP Packet pointer * \param Length Length of the packet */ -void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Header, int Length) +int TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Header, int Length) { int dataLen; Uint32 sequence_num; @@ -372,7 +423,11 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head // TODO: Check if this needs to be here if( Connection->State == TCP_ST_FINISHED ) { Log_Log("TCP", "Packet ignored - connection finnished"); - return ; + return 1; + } + if( Connection->State == TCP_ST_FORCE_CLOSE ) { + Log_Log("TCP", "Packet ignored - connection reset"); + return 1; } // Syncronise sequence values @@ -423,40 +478,49 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head if( Header->Flags & TCP_FLAG_ACK ) { Log_Log("TCP", "ACKing SYN-ACK"); - Connection->State = TCP_ST_OPEN; + Connection->State = TCP_ST_ESTABLISHED; VFS_MarkFull(&Connection->Node, 0); + TCP_INT_SendACK(Connection, "SYN-ACK"); } else { Log_Log("TCP", "ACKing SYN"); Connection->State = TCP_ST_SYN_RCVD; + TCP_INT_SendACK(Connection, "SYN"); } - Header->DestPort = Header->SourcePort; - Header->SourcePort = htons(Connection->LocalPort); - Header->AcknowlegementNumber = htonl(Connection->NextSequenceRcv); - Header->SequenceNumber = htonl(Connection->NextSequenceSend); - Header->WindowSize = htons(TCP_WINDOW_SIZE); - Header->Flags = TCP_FLAG_ACK; - Header->DataOffset = (sizeof(tTCPHeader)/4) << 4; - TCP_SendPacket( Connection, Header, 0, NULL ); } break; // SYN-ACK sent, expecting ACK case TCP_ST_SYN_RCVD: + if( Header->Flags & TCP_FLAG_RST ) + { + Log_Log("TCP", "RST Received, closing"); + Connection->State = TCP_ST_FORCE_CLOSE; + VFS_MarkError(&Connection->Node, 1); + return 0; + } if( Header->Flags & TCP_FLAG_ACK ) { // TODO: Handle max half-open limit Log_Log("TCP", "Connection fully opened"); - Connection->State = TCP_ST_OPEN; + Connection->State = TCP_ST_ESTABLISHED; VFS_MarkFull(&Connection->Node, 0); } break; // --- Established State --- - case TCP_ST_OPEN: + case TCP_ST_ESTABLISHED: // - Handle State changes // + if( Header->Flags & TCP_FLAG_RST ) + { + Log_Log("TCP", "Conn %p closed, received RST"); + // Error outstanding transactions + Connection->State = TCP_ST_FORCE_CLOSE; + VFS_MarkError(&Connection->Node, 1); + return 0; + } if( Header->Flags & TCP_FLAG_FIN ) { Log_Log("TCP", "Conn %p closed, recieved FIN", Connection); VFS_MarkError(&Connection->Node, 1); @@ -464,7 +528,7 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head TCP_INT_SendACK(Connection, "FIN Received"); Connection->State = TCP_ST_CLOSE_WAIT; // CLOSE WAIT requires the client to close - return ; + return 0; } // Check for an empty packet @@ -472,7 +536,7 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head if( Header->Flags == TCP_FLAG_ACK ) { Log_Log("TCP", "ACK only packet"); - return ; + return 0; } // TODO: Is this right? (empty packet counts as one byte) if( Connection->HighestSequenceRcvd == Connection->NextSequenceRcv ) @@ -480,7 +544,7 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head Connection->NextSequenceRcv ++; Log_Log("TCP", "Empty Packet, inc and ACK the current sequence number"); TCP_INT_SendACK(Connection, "Empty"); - return ; + return 0; } // NOTES: @@ -522,7 +586,9 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head #if 1 // - Only send an ACK if we've had a burst - if( Connection->NextSequenceRcv > (Uint32)(TCP_DACK_THRESHOLD + Connection->LastACKSequence) ) + Uint32 bytes_since_last_ack = Connection->NextSequenceRcv - Connection->LastACKSequence; + LOG("bytes_since_last_ack = 0x%x", bytes_since_last_ack); + if( bytes_since_last_ack > TCP_DACK_THRESHOLD ) { TCP_INT_SendACK(Connection, "DACK Burst"); // - Extend TCP deferred ACK timer @@ -535,14 +601,13 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head #endif } // Check if the packet is in window - else if( WrapBetween(Connection->NextSequenceRcv, sequence_num, - Connection->NextSequenceRcv+TCP_WINDOW_SIZE, 0xFFFFFFFF) ) + else if( sequence_num - Connection->NextSequenceRcv < TCP_WINDOW_SIZE ) { Uint8 *dataptr = (Uint8*)Header + (Header->DataOffset>>4)*4; - #if CACHE_FUTURE_PACKETS_IN_BYTES - Uint32 index; - - index = sequence_num % TCP_WINDOW_SIZE; + Uint32 index = sequence_num % TCP_WINDOW_SIZE; + Uint32 max = Connection->NextSequenceRcv % TCP_WINDOW_SIZE; + if( !(Connection->FuturePacketValidBytes[index/8] & (1 << (index%8))) ) + TCP_INT_SendACK(Connection, "Lost packet"); for( int i = 0; i < dataLen; i ++ ) { Connection->FuturePacketValidBytes[index/8] |= 1 << (index%8); @@ -550,52 +615,15 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head // Do a wrap increment index ++; if(index == TCP_WINDOW_SIZE) index = 0; + if(index == max) break; } - #else - tTCPStoredPacket *pkt, *tmp, *prev = NULL; - - // Allocate and fill cached packet - pkt = malloc( sizeof(tTCPStoredPacket) + dataLen ); - pkt->Next = NULL; - pkt->Sequence = ntohl(Header->SequenceNumber); - pkt->Length = dataLen; - memcpy(pkt->Data, dataptr, dataLen); - - Log_Log("TCP", "We missed a packet, caching", - pkt->Sequence, Connection->NextSequenceRcv); - - // No? Well, let's cache it and look at it later - SHORTLOCK( &Connection->lFuturePackets ); - for(tmp = Connection->FuturePackets; - tmp; - prev = tmp, tmp = tmp->Next) - { - if(tmp->Sequence >= pkt->Sequence) break; - } - - // Add if before first, or sequences don't match - if( !tmp || tmp->Sequence != pkt->Sequence ) - { - if(prev) - prev->Next = pkt; - else - Connection->FuturePackets = pkt; - pkt->Next = tmp; - } - // Replace if larger - else if(pkt->Length > tmp->Length) - { - if(prev) - prev->Next = pkt; - pkt->Next = tmp->Next; - free(tmp); - } - else + Uint32 rel_highest = Connection->HighestSequenceRcvd - Connection->NextSequenceRcv; + Uint32 rel_this = index - Connection->NextSequenceRcv; + LOG("Updating highest this(0x%x) > highest(%x)", rel_this, rel_highest); + if( rel_this > rel_highest ) { - free(pkt); // TODO: Find some way to remove this + Connection->HighestSequenceRcvd = index; } - SHORTREL( &Connection->lFuturePackets ); - #endif } // Badly out of sequence packet else @@ -633,14 +661,7 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head Log_Debug("TCP", "Conn %p closed, sent FIN and recieved FIN", Connection); VFS_MarkError(&Connection->Node, 1); - // ACK Packet - Header->DestPort = Header->SourcePort; - Header->SourcePort = htons(Connection->LocalPort); - Header->AcknowlegementNumber = Header->SequenceNumber; - Header->SequenceNumber = htonl(Connection->NextSequenceSend); - Header->WindowSize = htons(TCP_WINDOW_SIZE); - Header->Flags = TCP_FLAG_ACK; - TCP_SendPacket( Connection, Header, 0, NULL ); + TCP_INT_SendACK(Connection, "FINWAIT-1 FIN"); break ; } @@ -650,7 +671,7 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head Connection->State = TCP_ST_FIN_WAIT2; Log_Debug("TCP", "Conn %p closed, sent FIN ACKed", Connection); VFS_MarkError(&Connection->Node, 1); - return ; + return 0; } break; @@ -658,15 +679,8 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head if( Header->Flags & TCP_FLAG_FIN ) { Connection->State = TCP_ST_TIME_WAIT; - Log_Debug("TCP", "FIN sent and recieved, ACKing and going into TIME WAIT %p FINWAIT-2 -> TIME WAIT", Connection); - // Send ACK - Header->DestPort = Header->SourcePort; - Header->SourcePort = htons(Connection->LocalPort); - Header->AcknowlegementNumber = Header->SequenceNumber; - Header->SequenceNumber = htonl(Connection->NextSequenceSend); - Header->WindowSize = htons(TCP_WINDOW_SIZE); - Header->Flags = TCP_FLAG_ACK; - TCP_SendPacket( Connection, Header, 0, NULL ); + Log_Debug("TCP", "Conn %p FINWAIT-2 -> TIME WAIT", Connection); + TCP_INT_SendACK(Connection, "FINWAIT-2 FIN"); } break; @@ -677,7 +691,7 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head Connection->State = TCP_ST_TIME_WAIT; Log_Debug("TCP", "Conn %p CLOSING -> TIME WAIT", Connection); VFS_MarkError(&Connection->Node, 1); - return ; + return 0; } break; @@ -689,12 +703,17 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head case TCP_ST_FINISHED: Log_Log("TCP", "Packets when CLOSED, ignoring"); break; + case TCP_ST_FORCE_CLOSE: + Log_Log("TCP", "Packets when force CLOSED, ignoring"); + return 1; //default: // Log_Warning("TCP", "Unhandled TCP state %i", Connection->State); // break; } + return 0; + } /** @@ -736,17 +755,23 @@ int TCP_INT_AppendRecieved(tTCPConnection *Connection, const void *Data, size_t */ void TCP_INT_UpdateRecievedFromFuture(tTCPConnection *Connection) { - #if CACHE_FUTURE_PACKETS_IN_BYTES // Calculate length of contiguous bytes - int length = Connection->HighestSequenceRcvd - Connection->NextSequenceRcv; + const size_t length = Connection->HighestSequenceRcvd - Connection->NextSequenceRcv; Uint32 index = Connection->NextSequenceRcv % TCP_WINDOW_SIZE; - LOG("length=%i, index=%i", length, index); + size_t runlength = length; + LOG("HSR=0x%x,NSR=0x%x", Connection->HighestSequenceRcvd, Connection->NextSequenceRcv); + if( Connection->HighestSequenceRcvd == Connection->NextSequenceRcv ) + { + return ; + } + LOG("length=%u, index=0x%x", length, index); for( int i = 0; i < length; i ++ ) { int bit = index % 8; Uint8 bitfield_byte = Connection->FuturePacketValidBytes[index / 8]; if( (bitfield_byte & (1 << bit)) == 0 ) { - length = i; + runlength = i; + LOG("Hit missing, break"); break; } @@ -763,90 +788,51 @@ void TCP_INT_UpdateRecievedFromFuture(tTCPConnection *Connection) } index = Connection->NextSequenceRcv % TCP_WINDOW_SIZE; + Connection->NextSequenceRcv += runlength; // Write data to to the ring buffer - if( TCP_WINDOW_SIZE - index > length ) + if( TCP_WINDOW_SIZE - index > runlength ) { // Simple case - RingBuffer_Write( Connection->RecievedBuffer, Connection->FuturePacketData + index, length ); + RingBuffer_Write( Connection->RecievedBuffer, Connection->FuturePacketData + index, runlength ); } else { int endLen = TCP_WINDOW_SIZE - index; // 2-part case RingBuffer_Write( Connection->RecievedBuffer, Connection->FuturePacketData + index, endLen ); - RingBuffer_Write( Connection->RecievedBuffer, Connection->FuturePacketData, endLen - length ); + RingBuffer_Write( Connection->RecievedBuffer, Connection->FuturePacketData, endLen - runlength ); } // Mark (now saved) bytes as invalid // - Align index - while(index % 8 && length > 0) + while(index % 8 && runlength > 0) { Connection->FuturePacketData[index] = 0; Connection->FuturePacketValidBytes[index/8] &= ~(1 << (index%8)); index ++; if(index > TCP_WINDOW_SIZE) index -= TCP_WINDOW_SIZE; - length --; + runlength --; } - while( length > 7 ) + while( runlength > 7 ) { Connection->FuturePacketData[index] = 0; Connection->FuturePacketValidBytes[index/8] = 0; - length -= 8; + runlength -= 8; index += 8; if(index > TCP_WINDOW_SIZE) index -= TCP_WINDOW_SIZE; } - while(length) + while( runlength > 0) { Connection->FuturePacketData[index] = 0; Connection->FuturePacketData[index/8] &= ~(1 << (index%8)); index ++; if(index > TCP_WINDOW_SIZE) index -= TCP_WINDOW_SIZE; - length --; - } - - #else - tTCPStoredPacket *pkt; - for(;;) - { - SHORTLOCK( &Connection->lFuturePackets ); - - // Clear out duplicates from cache - // - If a packet has just been recieved, and it is expected, then - // (since NextSequenceRcv = rcvd->Sequence + rcvd->Length) all - // packets in cache that are smaller than the next expected - // are now defunct. - pkt = Connection->FuturePackets; - while(pkt && pkt->Sequence < Connection->NextSequenceRcv) - { - tTCPStoredPacket *next = pkt->Next; - free(pkt); - pkt = next; - } - - // If there's no packets left in cache, stop looking - if(!pkt || pkt->Sequence > Connection->NextSequenceRcv) { - SHORTREL( &Connection->lFuturePackets ); - return; - } - - // Delete packet from future list - Connection->FuturePackets = pkt->Next; - - // Release list - SHORTREL( &Connection->lFuturePackets ); - - // Looks like we found one - TCP_INT_AppendRecieved(Connection, pkt->Data, pkt->Length); - if( Connection->HighestSequenceRcvd == Connection->NextSequenceRcv ) - Connection->HighestSequenceRcvd += pkt->Length; - Connection->NextSequenceRcv += pkt->Length; - free(pkt); + runlength --; } - #endif } void TCP_int_SendDelayedACK(void *ConnPtr) @@ -939,6 +925,7 @@ tTCPConnection *TCP_int_CreateConnection(tInterface *Interface, enum eTCPConnect conn->LocalPort = -1; conn->RemotePort = -1; + conn->Node.Size = -1; conn->Node.ReferenceCount = 1; conn->Node.ImplPtr = conn; conn->Node.NumACLs = 1; @@ -952,6 +939,7 @@ tTCPConnection *TCP_int_CreateConnection(tInterface *Interface, enum eTCPConnect Semaphore_Init(conn->SentBufferSpace, 0, TCP_SEND_BUFFER_SIZE, "TCP SentBuffer", conn->Name); #endif + conn->HighestSequenceRcvd = 0; #if CACHE_FUTURE_PACKETS_IN_BYTES // Future recieved data (ahead of the expected sequence number) conn->FuturePacketData = (Uint8*)conn + sizeof(tTCPConnection); @@ -1201,7 +1189,8 @@ tVFS_Node *TCP_Client_Init(tInterface *Interface) conn->Server = NULL; conn->Prev = NULL; conn->Next = gTCP_OutbountCons; - gTCP_OutbountCons->Prev = conn; + if(gTCP_OutbountCons) + gTCP_OutbountCons->Prev = conn; gTCP_OutbountCons = conn; SHORTREL(&glTCP_OutbountCons); @@ -1218,13 +1207,14 @@ size_t TCP_Client_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffe tTCPConnection *conn = Node->ImplPtr; size_t len; - ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer); + ENTER("pNode XOffset xLength pBuffer", Node, Offset, Length, Buffer); LOG("conn = %p {State:%i}", conn, conn->State); // If the connection has been closed (state > ST_OPEN) then clear // any stale data in the buffer (until it is empty (until it is empty)) - if( conn->State > TCP_ST_OPEN ) + if( conn->State > TCP_ST_ESTABLISHED ) { + LOG("Connection closed"); Mutex_Acquire( &conn->lRecievedPackets ); len = RingBuffer_Read( Buffer, conn->RecievedBuffer, Length ); Mutex_Release( &conn->lRecievedPackets ); @@ -1279,6 +1269,8 @@ void TCP_INT_SendDataPacket(tTCPConnection *Connection, size_t Length, const voi // - Stop Delayed ACK timer (as this data packet ACKs) Time_RemoveTimer(Connection->DeferredACKTimer); + + // TODO: Don't exceed window size packet->SourcePort = htons(Connection->LocalPort); packet->DestPort = htons(Connection->RemotePort); @@ -1299,6 +1291,8 @@ void TCP_INT_SendDataPacket(tTCPConnection *Connection, size_t Length, const voi TCP_SendPacket( Connection, packet, Length, Data ); + // TODO: Start a retransmit time (if data is not ACKed in x seconds, send again) + Connection->NextSequenceSend += Length; } @@ -1318,7 +1312,7 @@ size_t TCP_Client_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void // #endif // Don't allow a write to a closed connection - if( conn->State > TCP_ST_OPEN ) { + if( conn->State > TCP_ST_ESTABLISHED ) { VFS_MarkError(Node, 1); errno = 0; LEAVE('i', -1); @@ -1475,8 +1469,9 @@ void TCP_Client_Close(tVFS_Node *Node) LEAVE('-'); return ; } + Node->ReferenceCount --; - if( conn->State == TCP_ST_CLOSE_WAIT || conn->State == TCP_ST_OPEN ) + if( conn->State == TCP_ST_CLOSE_WAIT || conn->State == TCP_ST_ESTABLISHED ) { packet.SourcePort = htons(conn->LocalPort); packet.DestPort = htons(conn->RemotePort); @@ -1498,13 +1493,18 @@ void TCP_Client_Close(tVFS_Node *Node) Log_Warning("TCP", "Closing connection that was never opened"); TCP_int_FreeTCB(conn); break; + case TCP_ST_FORCE_CLOSE: + conn->State = TCP_ST_FINISHED; + TCP_int_FreeTCB(conn); + break; case TCP_ST_CLOSE_WAIT: conn->State = TCP_ST_LAST_ACK; break; - case TCP_ST_OPEN: + case TCP_ST_ESTABLISHED: conn->State = TCP_ST_FIN_WAIT1; while( conn->State == TCP_ST_FIN_WAIT1 ) Threads_Yield(); + // No free, freed after TIME_WAIT break; default: Log_Warning("TCP", "Unhandled connection state %i in TCP_Client_Close", @@ -1552,3 +1552,10 @@ int WrapBetween(Uint32 Lower, Uint32 Value, Uint32 Higher, Uint32 MaxValue) return 0; } +Uint32 GetRelative(Uint32 Base, Uint32 Value) +{ + if( Value < Base ) + return Value - Base + 0xFFFFFFFF; + else + return Value - Base; +}