X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=KernelLand%2FModules%2FIPStack%2Ftcp.c;h=f1eee656d7b0a7633040305bb1605a51eafd6f51;hb=da91486679507cd3dc4a139318e05ce04e151145;hp=ee71bc7f25ea2ac372ebf3cb663c8dc27214dd4a;hpb=849329d50395b44ac97c5b5145fc2df0749eace2;p=tpg%2Facess2.git diff --git a/KernelLand/Modules/IPStack/tcp.c b/KernelLand/Modules/IPStack/tcp.c index ee71bc7f..f1eee656 100644 --- a/KernelLand/Modules/IPStack/tcp.c +++ b/KernelLand/Modules/IPStack/tcp.c @@ -2,7 +2,7 @@ * Acess2 IP Stack * - TCP Handling */ -#define DEBUG 1 +#define DEBUG 0 #include "ipstack.h" #include "ipv4.h" #include "ipv6.h" @@ -18,7 +18,9 @@ #define TCP_MAX_PACKET_SIZE 1024 #define TCP_WINDOW_SIZE 0x2000 -#define TCP_RECIEVE_BUFFER_SIZE 0x4000 +#define TCP_RECIEVE_BUFFER_SIZE 0x8000 +#define TCP_DACK_THRESHOLD 4096 +#define TCP_DACK_TIMEOUT 500 // === PROTOTYPES === void TCP_Initialise(void); @@ -28,12 +30,13 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe void 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_SendACK(tTCPConnection *Connection); Uint16 TCP_GetUnusedPort(); int TCP_AllocatePort(Uint16 Port); int TCP_DeallocatePort(Uint16 Port); // --- Server tVFS_Node *TCP_Server_Init(tInterface *Interface); -char *TCP_Server_ReadDir(tVFS_Node *Node, int Pos); + int TCP_Server_ReadDir(tVFS_Node *Node, int Pos, char Name[FILENAME_MAX]); tVFS_Node *TCP_Server_FindDir(tVFS_Node *Node, const char *Name); int TCP_Server_IOCtl(tVFS_Node *Node, int ID, void *Data); void TCP_Server_Close(tVFS_Node *Node); @@ -105,7 +108,7 @@ void TCP_SendPacket( tTCPConnection *Conn, tTCPHeader *Header, size_t Length, co IPStack_Buffer_AppendSubBuffer(buffer, Length, 0, Data, NULL, NULL); IPStack_Buffer_AppendSubBuffer(buffer, sizeof(*Header), 0, Header, NULL, NULL); - Log_Debug("TCP", "Sending %i+%i to %s:%i", sizeof(*Header), Length, + LOG("Sending %i+%i to %s:%i", sizeof(*Header), Length, IPStack_PrintAddress(Conn->Interface->Type, &Conn->RemoteIP), Conn->RemotePort ); @@ -161,7 +164,7 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe tTCPListener *srv; tTCPConnection *conn; - Log_Log("TCP", "TCP_GetPacket: :%i from [%s]:%i, Flags= %s%s%s%s%s%s%s%s", + Log_Log("TCP", "TCP_GetPacket: :%i from [%s]:%i, Flags = %s%s%s%s%s%s%s%s", ntohs(hdr->DestPort), IPStack_PrintAddress(Interface->Type, Address), ntohs(hdr->SourcePort), @@ -177,7 +180,7 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe if( Length > (hdr->DataOffset >> 4)*4 ) { - Log_Log("TCP", "TCP_GetPacket: SequenceNumber = 0x%x", ntohl(hdr->SequenceNumber)); + LOG("SequenceNumber = 0x%x", ntohl(hdr->SequenceNumber)); #if HEXDUMP_INCOMING Debug_HexDump( "TCP_GetPacket: Packet Data = ", @@ -273,6 +276,7 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe 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; @@ -331,18 +335,22 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head // Syncronise sequence values if(Header->Flags & TCP_FLAG_SYN) { // TODO: What if the packet also has data? + if( Connection->LastACKSequence != Connection->NextSequenceRcv ) + TCP_INT_SendACK(Connection); Connection->NextSequenceRcv = ntohl(Header->SequenceNumber); + Connection->LastACKSequence = Connection->NextSequenceRcv; } // Ackowledge a sent packet if(Header->Flags & TCP_FLAG_ACK) { // TODO: Process an ACKed Packet - Log_Log("TCP", "Conn %p, Sent packet 0x%x ACKed", Connection, Header->AcknowlegementNumber); + LOG("Conn %p, Sent packet 0x%x ACKed", Connection, Header->AcknowlegementNumber); } // Get length of data dataLen = Length - (Header->DataOffset>>4)*4; - Log_Log("TCP", "HandleConnectionPacket - dataLen = %i", dataLen); + LOG("dataLen = %i", dataLen); +// Log_Debug("TCP", "State %i, dataLen = %x", Connection->State, dataLen); // // State Machine @@ -373,6 +381,7 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head { Log_Log("TCP", "ACKing SYN-ACK"); Connection->State = TCP_ST_OPEN; + VFS_MarkFull(&Connection->Node, 0); } else { @@ -387,8 +396,9 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head if( Header->Flags & TCP_FLAG_ACK ) { // TODO: Handle max half-open limit - Connection->State = TCP_ST_OPEN; Log_Log("TCP", "Connection fully opened"); + Connection->State = TCP_ST_OPEN; + VFS_MarkFull(&Connection->Node, 0); } break; @@ -432,7 +442,7 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head sequence_num = ntohl(Header->SequenceNumber); - Log_Log("TCP", "0x%08x <= 0x%08x < 0x%08x", + LOG("TCP", "0x%08x <= 0x%08x < 0x%08x", Connection->NextSequenceRcv, ntohl(Header->SequenceNumber), Connection->NextSequenceRcv + TCP_WINDOW_SIZE @@ -448,9 +458,10 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head dataLen ); if(rv != 0) { + Log_Notice("TCP", "TCP_INT_AppendRecieved rv %i", rv); break; } - Log_Log("TCP", "0x%08x += %i", Connection->NextSequenceRcv, dataLen); + LOG("0x%08x += %i", Connection->NextSequenceRcv, dataLen); Connection->NextSequenceRcv += dataLen; // TODO: This should be moved out of the watcher thread, @@ -458,18 +469,20 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head // 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 - 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_SYN; // Eliminate all flags save for SYN - Header->Flags |= TCP_FLAG_ACK; // Add ACK - Log_Log("TCP", "Sending ACK for 0x%08x", Connection->NextSequenceRcv); - TCP_SendPacket( Connection, Header, 0, NULL ); - //Connection->NextSequenceSend ++; + + #if 1 + // - Only send an ACK if we've had a burst + if( Connection->NextSequenceRcv > (Uint32)(TCP_DACK_THRESHOLD + Connection->LastACKSequence) ) + { + TCP_INT_SendACK(Connection); + // - Extend TCP deferred ACK timer + Time_RemoveTimer(Connection->DeferredACKTimer); + } + // - Schedule the deferred ACK timer (if already scheduled, this is a NOP) + Time_ScheduleTimer(Connection->DeferredACKTimer, TCP_DACK_TIMEOUT); + #else + TCP_INT_SendACK(Connection); + #endif } // Check if the packet is in window else if( WrapBetween(Connection->NextSequenceRcv, sequence_num, @@ -540,7 +553,8 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head { Log_Log("TCP", "Fully out of sequence packet (0x%08x not between 0x%08x and 0x%08x), dropped", sequence_num, Connection->NextSequenceRcv, Connection->NextSequenceRcv+TCP_WINDOW_SIZE); - // TODO: Spec says we should send an empty ACK with the current state + // Spec says we should send an empty ACK with the current state + TCP_INT_SendACK(Connection); } break; @@ -780,6 +794,25 @@ void TCP_INT_UpdateRecievedFromFuture(tTCPConnection *Connection) #endif } +void TCP_INT_SendACK(tTCPConnection *Connection) +{ + tTCPHeader hdr; + // ACK Packet + hdr.DataOffset = (sizeof(tTCPHeader)/4) << 4; + hdr.DestPort = htons(Connection->RemotePort); + hdr.SourcePort = htons(Connection->LocalPort); + hdr.AcknowlegementNumber = htonl(Connection->NextSequenceRcv); + hdr.SequenceNumber = htonl(Connection->NextSequenceSend); + hdr.WindowSize = htons(TCP_WINDOW_SIZE); + hdr.Flags = TCP_FLAG_ACK; // TODO: Determine if SYN is wanted too + hdr.Checksum = 0; // TODO: Checksum + hdr.UrgentPointer = 0; + Log_Debug("TCP", "Sending ACK for 0x%08x", Connection->NextSequenceRcv); + TCP_SendPacket( Connection, &hdr, 0, NULL ); + //Connection->NextSequenceSend ++; + Connection->LastACKSequence = Connection->NextSequenceRcv; +} + /** * \fn Uint16 TCP_GetUnusedPort() * \brief Gets an unused port and allocates it @@ -877,24 +910,17 @@ tVFS_Node *TCP_Server_Init(tInterface *Interface) * \param Node Server node * \param Pos Position (ignored) */ -char *TCP_Server_ReadDir(tVFS_Node *Node, int Pos) +int TCP_Server_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]) { tTCPListener *srv = Node->ImplPtr; tTCPConnection *conn; - char *ret; ENTER("pNode iPos", Node, Pos); Log_Log("TCP", "Thread %i waiting for a connection", Threads_GetTID()); - for(;;) - { - SHORTLOCK( &srv->lConnections ); - if( srv->NewConnections != NULL ) break; - SHORTREL( &srv->lConnections ); - Threads_Yield(); // TODO: Sleep until poked - } + Semaphore_Wait( &srv->WaitingConnections, 1 ); - + SHORTLOCK(&srv->lConnections); // Increment the new list (the current connection is still on the // normal list) conn = srv->NewConnections; @@ -910,11 +936,10 @@ char *TCP_Server_ReadDir(tVFS_Node *Node, int Pos) LOG("srv->NewConnections = %p", srv->NewConnections); LOG("srv->ConnectionsTail = %p", srv->ConnectionsTail); - ret = malloc(9); - itoa(ret, conn->Node.ImplInt, 16, 8, '0'); - Log_Log("TCP", "Thread %i got '%s'", Threads_GetTID(), ret); - LEAVE('s', ret); - return ret; + itoa(Dest, conn->Node.ImplInt, 16, 8, '0'); + Log_Log("TCP", "Thread %i got connection '%s'", Threads_GetTID(), Dest); + LEAVE('i', 0); + return 0; } /** @@ -1048,6 +1073,7 @@ tVFS_Node *TCP_Client_Init(tInterface *Interface) conn->Node.NumACLs = 1; conn->Node.ACLs = &gVFS_ACL_EveryoneRW; conn->Node.Type = &gTCP_ClientNodeType; + conn->Node.BufferFull = 1; // Cleared when connection opens conn->RecievedBuffer = RingBuffer_Create( TCP_RECIEVE_BUFFER_SIZE ); #if 0 @@ -1061,6 +1087,8 @@ tVFS_Node *TCP_Client_Init(tInterface *Interface) conn->FuturePacketValidBytes = conn->FuturePacketData + TCP_WINDOW_SIZE; #endif + conn->DeferredACKTimer = Time_AllocateTimer( (void(*)(void*)) TCP_INT_SendACK, conn); + SHORTLOCK(&glTCP_OutbountCons); conn->Next = gTCP_OutbountCons; gTCP_OutbountCons = conn; @@ -1082,14 +1110,9 @@ size_t TCP_Client_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffe ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer); LOG("conn = %p {State:%i}", conn, conn->State); - // 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 ) + // 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 ) { Mutex_Acquire( &conn->lRecievedPackets ); len = RingBuffer_Read( Buffer, conn->RecievedBuffer, Length ); @@ -1168,16 +1191,16 @@ size_t TCP_Client_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void // Buffer, Length); // #endif - // Check if connection is open - while( conn->State == TCP_ST_SYN_RCVD || conn->State == TCP_ST_SYN_SENT ) - Threads_Yield(); - - if( conn->State != TCP_ST_OPEN ) { + // Don't allow a write to a closed connection + if( conn->State > TCP_ST_OPEN ) { VFS_MarkError(Node, 1); LEAVE('i', -1); return -1; } + // Wait + VFS_SelectNode(Node, VFS_SELECT_WRITE|VFS_SELECT_ERROR, NULL, "TCP_Client_Write"); + do { int len = (rem < TCP_MAX_PACKET_SIZE) ? rem : TCP_MAX_PACKET_SIZE; @@ -1282,13 +1305,10 @@ int TCP_Client_IOCtl(tVFS_Node *Node, int ID, void *Data) LEAVE_RET('i', 0); { - tTime timeout_end = now() + conn->Interface->TimeoutDelay; + tTime timeout = conn->Interface->TimeoutDelay; TCP_StartConnection(conn); - // TODO: Wait for connection to open - while( conn->State == TCP_ST_SYN_SENT && timeout_end > now() ) { - Threads_Yield(); - } + VFS_SelectNode(&conn->Node, VFS_SELECT_WRITE, &timeout, "TCP Connection"); if( conn->State == TCP_ST_SYN_SENT ) LEAVE_RET('i', 0); } @@ -1334,10 +1354,13 @@ void TCP_Client_Close(tVFS_Node *Node) while( conn->State == TCP_ST_FIN_WAIT1 ) Threads_Yield(); break; default: - Log_Warning("TCP", "Unhandled connection state in TCP_Client_Close"); + Log_Warning("TCP", "Unhandled connection state %i in TCP_Client_Close", + conn->State); break; } + Time_RemoveTimer(conn->DeferredACKTimer); + Time_FreeTimer(conn->DeferredACKTimer); free(conn); LEAVE('-');