X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Modules%2FIPStack%2Ftcp.c;h=83a71b640851e3444fd72b5d2e7b348bd55dde7b;hb=4f1a9b430a3fa57bbe52a6a2fe546f6fe93c389d;hp=1662ca01b040f6a475811689acf3c8dbdb1cb2d1;hpb=15eb3bb8363aa44fa0c8cfacbdc99966f5057e51;p=tpg%2Facess2.git diff --git a/Modules/IPStack/tcp.c b/Modules/IPStack/tcp.c index 1662ca01..83a71b64 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); @@ -364,13 +365,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 +387,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; @@ -425,8 +426,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 +479,7 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head free(pkt); } SHORTREL( &Connection->lFuturePackets ); + #endif } // Badly out of sequence packet else @@ -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 nope, then clean out the recieved buffer if( conn->State != TCP_ST_OPEN ) { Mutex_Acquire( &conn->lRecievedPackets ); @@ -938,10 +1037,8 @@ Uint64 TCP_Client_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buff // Wait VFS_SelectNode(Node, VFS_SELECT_READ, 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 ) { @@ -1004,13 +1101,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;