X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Modules%2FIPStack%2Ftcp.c;h=8ebf0aee9fefe4f75af4689b994bf86d8e3a2312;hb=de86ddb7cb10ee403732f9207aba756f267ef3de;hp=1662ca01b040f6a475811689acf3c8dbdb1cb2d1;hpb=15eb3bb8363aa44fa0c8cfacbdc99966f5057e51;p=tpg%2Facess2.git diff --git a/Modules/IPStack/tcp.c b/Modules/IPStack/tcp.c index 1662ca01..8ebf0aee 100644 --- a/Modules/IPStack/tcp.c +++ b/Modules/IPStack/tcp.c @@ -8,6 +8,7 @@ #include "tcp.h" #define USE_SELECT 1 +#define CACHE_FUTURE_PACKETS_IN_BYTES 1 // Use a ring buffer to cache out of order packets #define TCP_MIN_DYNPORT 0xC000 #define TCP_MAX_HALFOPEN 1024 // Should be enough @@ -17,7 +18,7 @@ #define TCP_RECIEVE_BUFFER_SIZE 0x4000 // === PROTOTYPES === -void TCP_Initialise(); +void TCP_Initialise(void); void TCP_StartConnection(tTCPConnection *Conn); void TCP_SendPacket(tTCPConnection *Conn, size_t Length, tTCPHeader *Data); void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer); @@ -61,7 +62,7 @@ Uint32 gaTCP_PortBitmap[0x800]; * * Registers the client and server files and the GetPacket callback */ -void TCP_Initialise() +void TCP_Initialise(void) { IPStack_AddFile(&gTCP_ServerFile); IPStack_AddFile(&gTCP_ClientFile); @@ -353,9 +354,10 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head // - Handle State changes // if( Header->Flags & TCP_FLAG_FIN ) { - Log_Log("TCP", "Conn %p closed, recieved FIN, acknowledging", Connection); + Log_Log("TCP", "Conn %p closed, recieved FIN", Connection); VFS_MarkError(&Connection->Node, 1); Connection->State = TCP_ST_CLOSE_WAIT; +// Header->Flags &= ~TCP_FLAG_FIN; // CLOSE WAIT requires the client to close (or does it?) #if 0 @@ -364,13 +366,13 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head // Check for an empty packet if(dataLen == 0) { - if( Header->Flags != TCP_FLAG_ACK ) + if( Header->Flags == TCP_FLAG_ACK ) { - Connection->NextSequenceRcv ++; // TODO: Is this right? (empty packet counts as one byte) - Log_Log("TCP", "Empty Packet, inc and ACK the current sequence number"); + Log_Log("TCP", "ACK only packet"); + return ; } - else - Log_Log("TCP", "Empty Packet, just ACKing the current sequence number"); + Connection->NextSequenceRcv ++; // TODO: Is this right? (empty packet counts as one byte) + Log_Log("TCP", "Empty Packet, inc and ACK the current sequence number"); Header->DestPort = Header->SourcePort; Header->SourcePort = htons(Connection->LocalPort); Header->AcknowlegementNumber = htonl(Connection->NextSequenceRcv); @@ -386,7 +388,7 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head // /NOTES // Allocate and fill cached packet - pkt = malloc( dataLen + sizeof(tTCPStoredPacket) ); + pkt = malloc( sizeof(tTCPStoredPacket) + dataLen ); pkt->Next = NULL; pkt->Sequence = ntohl(Header->SequenceNumber); pkt->Length = dataLen; @@ -410,6 +412,7 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head // TODO: This should be moved out of the watcher thread, // so that a single lost packet on one connection doesn't cause // all connections on the interface to lag. + // - Meh, no real issue, as the cache shouldn't be that large TCP_INT_UpdateRecievedFromFuture(Connection); // ACK Packet @@ -425,8 +428,23 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head //Connection->NextSequenceSend ++; } // Check if the packet is in window - else if( WrapBetween(Connection->NextSequenceRcv, pkt->Sequence, Connection->NextSequenceRcv+TCP_WINDOW_SIZE, 0xFFFFFFFF) ) + else if( WrapBetween(Connection->NextSequenceRcv, pkt->Sequence, + Connection->NextSequenceRcv+TCP_WINDOW_SIZE, 0xFFFFFFFF) ) { + #if CACHE_FUTURE_PACKETS_IN_BYTES + Uint32 index; + int i; + + index = pkt->Sequence % TCP_WINDOW_SIZE; + for( i = 0; i < pkt->Length; i ++ ) + { + Connection->FuturePacketValidBytes[index/8] |= 1 << (index%8); + Connection->FuturePacketValidBytes[index] = pkt->Data[i]; + // Do a wrap increment + index ++; + if(index == TCP_WINDOW_SIZE) index = 0; + } + #else tTCPStoredPacket *tmp, *prev = NULL; Log_Log("TCP", "We missed a packet, caching", @@ -463,6 +481,7 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head free(pkt); } SHORTREL( &Connection->lFuturePackets ); + #endif } // Badly out of sequence packet else @@ -503,7 +522,7 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head // ACK Packet Header->DestPort = Header->SourcePort; Header->SourcePort = htons(Connection->LocalPort); - Header->AcknowlegementNumber = htonl(Connection->NextSequenceRcv); + Header->AcknowlegementNumber = Header->SequenceNumber; Header->SequenceNumber = htonl(Connection->NextSequenceSend); Header->WindowSize = htons(TCP_WINDOW_SIZE); Header->Flags = TCP_FLAG_ACK; @@ -529,7 +548,7 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head // Send ACK Header->DestPort = Header->SourcePort; Header->SourcePort = htons(Connection->LocalPort); - Header->AcknowlegementNumber = htonl(Connection->NextSequenceRcv); + Header->AcknowlegementNumber = Header->SequenceNumber; Header->SequenceNumber = htonl(Connection->NextSequenceSend); Header->WindowSize = htons(TCP_WINDOW_SIZE); Header->Flags = TCP_FLAG_ACK; @@ -583,9 +602,7 @@ void TCP_INT_AppendRecieved(tTCPConnection *Connection, tTCPStoredPacket *Pkt) RingBuffer_Write( Connection->RecievedBuffer, Pkt->Data, Pkt->Length ); - #if USE_SELECT VFS_MarkAvaliable(&Connection->Node, 1); - #endif Mutex_Release( &Connection->lRecievedPackets ); } @@ -600,6 +617,75 @@ void TCP_INT_AppendRecieved(tTCPConnection *Connection, tTCPStoredPacket *Pkt) */ void TCP_INT_UpdateRecievedFromFuture(tTCPConnection *Connection) { + #if CACHE_FUTURE_PACKETS_IN_BYTES + int i, length = 0; + Uint32 index; + + // Calculate length of contiguous bytes + length = Connection->HighestSequenceRcvd - Connection->NextSequenceRcv; + index = Connection->NextSequenceRcv % TCP_WINDOW_SIZE; + for( i = 0; i < length; i ++ ) + { + if( Connection->FuturePacketValidBytes[i / 8] == 0xFF ) { + i += 7; index += 7; + continue; + } + else if( !(Connection->FuturePacketValidBytes[i / 8] & (1 << (i%8))) ) + break; + + index ++; + if(index > TCP_WINDOW_SIZE) + index -= TCP_WINDOW_SIZE; + } + length = i; + + index = Connection->NextSequenceRcv % TCP_WINDOW_SIZE; + + // Write data to to the ring buffer + if( TCP_WINDOW_SIZE - index > length ) + { + // Simple case + RingBuffer_Write( Connection->RecievedBuffer, Connection->FuturePacketData + index, length ); + } + 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 ); + } + + // Mark (now saved) bytes as invalid + // - Align index + while(index % 8 && length) + { + Connection->FuturePacketData[index] = 0; + Connection->FuturePacketData[index/8] &= ~(1 << (index%8)); + index ++; + if(index > TCP_WINDOW_SIZE) + index -= TCP_WINDOW_SIZE; + length --; + } + while( length > 7 ) + { + Connection->FuturePacketData[index] = 0; + Connection->FuturePacketValidBytes[index/8] = 0; + length -= 8; + index += 8; + if(index > TCP_WINDOW_SIZE) + index -= TCP_WINDOW_SIZE; + } + while(length) + { + 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(;;) { @@ -635,6 +721,7 @@ void TCP_INT_UpdateRecievedFromFuture(tTCPConnection *Connection) Connection->NextSequenceRcv += pkt->Length; free(pkt); } + #endif } /** @@ -876,13 +963,12 @@ void TCP_Server_Close(tVFS_Node *Node) */ tVFS_Node *TCP_Client_Init(tInterface *Interface) { - tTCPConnection *conn = malloc( sizeof(tTCPConnection) ); + tTCPConnection *conn = calloc( sizeof(tTCPConnection) + TCP_WINDOW_SIZE + TCP_WINDOW_SIZE/8, 1 ); conn->State = TCP_ST_CLOSED; conn->Interface = Interface; conn->LocalPort = -1; conn->RemotePort = -1; - memset( &conn->RemoteIP, 0, sizeof(conn->RemoteIP) ); conn->Node.ImplPtr = conn; conn->Node.NumACLs = 1; @@ -893,6 +979,16 @@ tVFS_Node *TCP_Client_Init(tInterface *Interface) conn->Node.Close = TCP_Client_Close; conn->RecievedBuffer = RingBuffer_Create( TCP_RECIEVE_BUFFER_SIZE ); + #if 0 + conn->SentBuffer = RingBuffer_Create( TCP_SEND_BUFFER_SIZE ); + Semaphore_Init(conn->SentBufferSpace, 0, TCP_SEND_BUFFER_SIZE, "TCP SentBuffer", conn->Name); + #endif + + #if CACHE_FUTURE_PACKETS_IN_BYTES + // Future recieved data (ahead of the expected sequence number) + conn->FuturePacketData = (Uint8*)conn + sizeof(tTCPConnection); + conn->FuturePacketValidBytes = conn->FuturePacketData + TCP_WINDOW_SIZE; + #endif SHORTLOCK(&glTCP_OutbountCons); conn->Next = gTCP_OutbountCons; @@ -915,10 +1011,13 @@ Uint64 TCP_Client_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buff ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer); LOG("conn = %p {State:%i}", conn, conn->State); - // Check if connection is open + // Check if connection is estabilishing + // - TODO: Sleep instead (maybe using VFS_SelectNode to wait for the + // data to be availiable while( conn->State == TCP_ST_SYN_RCVD || conn->State == TCP_ST_SYN_SENT ) Threads_Yield(); + // If the conneciton is not open, then clean out the recieved buffer if( conn->State != TCP_ST_OPEN ) { Mutex_Acquire( &conn->lRecievedPackets ); @@ -936,12 +1035,10 @@ Uint64 TCP_Client_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buff } // Wait - VFS_SelectNode(Node, VFS_SELECT_READ, NULL, "TCP_Client_Read"); + VFS_SelectNode(Node, VFS_SELECT_READ|VFS_SELECT_ERROR, NULL, "TCP_Client_Read"); - // Lock list and read + // Lock list and read as much as possible (up to `Length`) Mutex_Acquire( &conn->lRecievedPackets ); - - // Attempt to read all `Length` bytes len = RingBuffer_Read( Buffer, conn->RecievedBuffer, Length ); if( len == 0 || conn->RecievedBuffer->Length == 0 ) { @@ -994,6 +1091,11 @@ Uint64 TCP_Client_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buf ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer); +// #if DEBUG +// Debug_HexDump("TCP_Client_Write: Buffer = ", +// Buffer, Length); +// #endif + // Check if connection is open while( conn->State == TCP_ST_SYN_RCVD || conn->State == TCP_ST_SYN_SENT ) Threads_Yield(); @@ -1004,13 +1106,24 @@ Uint64 TCP_Client_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buf return -1; } - while( rem > TCP_MAX_PACKET_SIZE ) + do { - TCP_INT_SendDataPacket(conn, TCP_MAX_PACKET_SIZE, Buffer); - Buffer += TCP_MAX_PACKET_SIZE; - } - - TCP_INT_SendDataPacket(conn, rem, Buffer); + int len = (rem < TCP_MAX_PACKET_SIZE) ? rem : TCP_MAX_PACKET_SIZE; + + #if 0 + // Wait for space in the buffer + Semaphore_Signal( &Connection->SentBufferSpace, len ); + + // Save data to buffer (and update the length read by the ammount written) + len = RingBuffer_Write( &Connection->SentBuffer, Buffer, len); + #endif + + // Send packet + TCP_INT_SendDataPacket(conn, len, Buffer); + + Buffer += len; + rem -= len; + } while( rem > 0 ); LEAVE('i', Length); return Length; @@ -1039,6 +1152,7 @@ void TCP_StartConnection(tTCPConnection *Conn) Conn->NextSequenceSend ++; Conn->State = TCP_ST_SYN_SENT; + return ; } @@ -1095,7 +1209,18 @@ int TCP_Client_IOCtl(tVFS_Node *Node, int ID, void *Data) if(conn->RemotePort == -1) LEAVE_RET('i', 0); - TCP_StartConnection(conn); + { + tTime timeout_end = now() + conn->Interface->TimeoutDelay; + + TCP_StartConnection(conn); + // TODO: Wait for connection to open + while( conn->State == TCP_ST_SYN_SENT && timeout_end > now() ) { + Threads_Yield(); + } + if( conn->State == TCP_ST_SYN_SENT ) + LEAVE_RET('i', 0); + } + LEAVE_RET('i', 1); // Get recieve buffer length @@ -1122,7 +1247,7 @@ void TCP_Client_Close(tVFS_Node *Node) packet.AcknowlegementNumber = 0; packet.SequenceNumber = htonl(conn->NextSequenceSend); - packet.Flags = TCP_FLAG_FIN|TCP_FLAG_ACK; + packet.Flags = TCP_FLAG_FIN; TCP_SendPacket( conn, sizeof(tTCPHeader), &packet ); } @@ -1130,7 +1255,7 @@ void TCP_Client_Close(tVFS_Node *Node) switch( conn->State ) { case TCP_ST_CLOSE_WAIT: - conn->State = TCP_ST_CLOSED; + conn->State = TCP_ST_LAST_ACK; break; case TCP_ST_OPEN: conn->State = TCP_ST_FIN_WAIT1;