X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Modules%2FIPStack%2Ftcp.c;h=1415deaacb933e94420441736a66bb7f041eabba;hb=31ca692f6ad721a25a48ef121534e02f6900efaf;hp=50eacbc64a33fcaff1d0ac4da6ed1eabc46d84c2;hpb=a200e721cb12cbfdb09e32089bd31b4ad84baa67;p=tpg%2Facess2.git diff --git a/Modules/IPStack/tcp.c b/Modules/IPStack/tcp.c index 50eacbc6..1415deaa 100644 --- a/Modules/IPStack/tcp.c +++ b/Modules/IPStack/tcp.c @@ -5,9 +5,13 @@ #define DEBUG 1 #include "ipstack.h" #include "ipv4.h" +#include "ipv6.h" #include "tcp.h" #define USE_SELECT 1 +#define HEXDUMP_INCOMING 0 +#define HEXDUMP_OUTGOING 0 +#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,12 +21,12 @@ #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); void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Header, int Length); -void TCP_INT_AppendRecieved(tTCPConnection *Connection, tTCPStoredPacket *Ptk); +int TCP_INT_AppendRecieved(tTCPConnection *Connection, const void *Data, size_t Length); void TCP_INT_UpdateRecievedFromFuture(tTCPConnection *Connection); Uint16 TCP_GetUnusedPort(); int TCP_AllocatePort(Uint16 Port); @@ -36,7 +40,7 @@ void TCP_Server_Close(tVFS_Node *Node); // --- Client tVFS_Node *TCP_Client_Init(tInterface *Interface); Uint64 TCP_Client_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer); -Uint64 TCP_Client_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer); +Uint64 TCP_Client_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer); int TCP_Client_IOCtl(tVFS_Node *Node, int ID, void *Data); void TCP_Client_Close(tVFS_Node *Node); // --- Helpers @@ -45,6 +49,20 @@ void TCP_Client_Close(tVFS_Node *Node); // === TEMPLATES === tSocketFile gTCP_ServerFile = {NULL, "tcps", TCP_Server_Init}; tSocketFile gTCP_ClientFile = {NULL, "tcpc", TCP_Client_Init}; +tVFS_NodeType gTCP_ServerNodeType = { + .TypeName = "TCP Server", + .ReadDir = TCP_Server_ReadDir, + .FindDir = TCP_Server_FindDir, + .IOCtl = TCP_Server_IOCtl, + .Close = TCP_Server_Close + }; +tVFS_NodeType gTCP_ClientNodeType = { + .TypeName = "TCP Client/Connection", + .Read = TCP_Client_Read, + .Write = TCP_Client_Write, + .IOCtl = TCP_Client_IOCtl, + .Close = TCP_Client_Close + }; // === GLOBALS === int giTCP_NumHalfopen = 0; @@ -61,11 +79,13 @@ Uint32 gaTCP_PortBitmap[0x800]; * * Registers the client and server files and the GetPacket callback */ -void TCP_Initialise() +void TCP_Initialise(void) { + giTCP_NextOutPort += rand()%32; IPStack_AddFile(&gTCP_ServerFile); IPStack_AddFile(&gTCP_ClientFile); IPv4_RegisterCallback(IP4PROT_TCP, TCP_GetPacket); + IPv6_RegisterCallback(IP4PROT_TCP, TCP_GetPacket); } /** @@ -76,22 +96,43 @@ void TCP_Initialise() */ void TCP_SendPacket( tTCPConnection *Conn, size_t Length, tTCPHeader *Data ) { - size_t buflen; - Uint32 *buf; + Uint16 checksum[2]; + + Data->Checksum = 0; + checksum[1] = htons( ~IPv4_Checksum( (void*)Data, Length ) ); // Partial checksum + if(Length & 1) + ((Uint8*)Data)[Length] = 0; + + // TODO: Fragment packet + switch( Conn->Interface->Type ) { - case 4: // Append IPv4 Pseudo Header - buflen = 4 + 4 + 4 + ((Length+1)&~1); - buf = malloc( buflen ); - buf[0] = ((tIPv4*)Conn->Interface->Address)->L; - buf[1] = Conn->RemoteIP.v4.L; - buf[2] = (htons(Length)<<16) | (6<<8) | 0; - Data->Checksum = 0; - memcpy( &buf[3], Data, Length ); - Data->Checksum = htons( IPv4_Checksum( buf, buflen ) ); - free(buf); + case 4: + // Append IPv4 Pseudo Header + { + Uint32 buf[3]; + buf[0] = ((tIPv4*)Conn->Interface->Address)->L; + buf[1] = Conn->RemoteIP.v4.L; + buf[2] = (htons(Length)<<16) | (6<<8) | 0; + checksum[0] = htons( ~IPv4_Checksum(buf, sizeof(buf)) ); // Partial checksum + } + Data->Checksum = htons( IPv4_Checksum(checksum, 2*2) ); // Combine the two IPv4_SendPacket(Conn->Interface, Conn->RemoteIP.v4, IP4PROT_TCP, 0, Length, Data); break; + + case 6: + // Append IPv6 Pseudo Header + { + Uint32 buf[4+4+1+1]; + memcpy(buf, Conn->Interface->Address, 16); + memcpy(&buf[4], &Conn->RemoteIP, 16); + buf[8] = htonl(Length); + buf[9] = htonl(6); + checksum[0] = htons( ~IPv4_Checksum(buf, sizeof(buf)) ); // Partial checksum + } + Data->Checksum = htons( IPv4_Checksum(checksum, 2*2) ); // Combine the two + IPv6_SendPacket(Conn->Interface, Conn->RemoteIP.v6, IP4PROT_TCP, Length, Data); + break; } } @@ -108,17 +149,10 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe tTCPListener *srv; tTCPConnection *conn; - Log_Log("TCP", "TCP_GetPacket: SourcePort = %i, DestPort = %i", - ntohs(hdr->SourcePort), ntohs(hdr->DestPort)); -/* - Log_Log("TCP", "TCP_GetPacket: SequenceNumber = 0x%x", ntohl(hdr->SequenceNumber)); - Log_Log("TCP", "TCP_GetPacket: AcknowlegementNumber = 0x%x", ntohl(hdr->AcknowlegementNumber)); - Log_Log("TCP", "TCP_GetPacket: DataOffset = %i", hdr->DataOffset >> 4); - Log_Log("TCP", "TCP_GetPacket: WindowSize = %i", htons(hdr->WindowSize)); - Log_Log("TCP", "TCP_GetPacket: Checksum = 0x%x", htons(hdr->Checksum)); - Log_Log("TCP", "TCP_GetPacket: UrgentPointer = 0x%x", htons(hdr->UrgentPointer)); -*/ - Log_Log("TCP", "TCP_GetPacket: 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->SourcePort), + IPStack_PrintAddress(Interface->Type, Address), + ntohs(hdr->DestPort), (hdr->Flags & TCP_FLAG_CWR) ? "CWR " : "", (hdr->Flags & TCP_FLAG_ECE) ? "ECE " : "", (hdr->Flags & TCP_FLAG_URG) ? "URG " : "", @@ -132,11 +166,13 @@ 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)); +#if HEXDUMP_INCOMING Debug_HexDump( - "[TCP ] Packet Data = ", + "TCP_GetPacket: Packet Data = ", (Uint8*)hdr + (hdr->DataOffset >> 4)*4, Length - (hdr->DataOffset >> 4)*4 ); +#endif } // Check Servers @@ -154,8 +190,6 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe // Is this in an established connection? for( conn = srv->Connections; conn; conn = conn->Next ) { - Log_Log("TCP", "TCP_GetPacket: conn->Interface(%p) == Interface(%p)", - conn->Interface, Interface); // Check that it is coming in on the same interface if(conn->Interface != Interface) continue; @@ -165,10 +199,8 @@ 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 ; Log_Log("TCP", "TCP_GetPacket: Matches connection %p", conn); // We have a response! @@ -208,9 +240,7 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe conn->Node.ACLs = &gVFS_ACL_EveryoneRW; conn->Node.ImplPtr = conn; conn->Node.ImplInt = srv->NextID ++; - conn->Node.Read = TCP_Client_Read; - conn->Node.Write = TCP_Client_Write; - //conn->Node.Close = TCP_SrvConn_Close; + conn->Node.Type = &gTCP_ClientNodeType; // TODO: Special type for the server end? // Hmm... Theoretically, this lock will never have to wait, // as the interface is locked to the watching thread, and this @@ -273,9 +303,9 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe * \param Length Length of the packet */ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Header, int Length) -{ - tTCPStoredPacket *pkt; +{ int dataLen; + Uint32 sequence_num; // Silently drop once finished // TODO: Check if this needs to be here @@ -305,7 +335,7 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head // switch( Connection->State ) { - // Pre-init conneciton? + // Pre-init connection? case TCP_ST_CLOSED: Log_Log("TCP", "Packets to a closed connection?!"); break; @@ -353,9 +383,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 +395,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); @@ -385,31 +416,33 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head // PSH - Has Data? // /NOTES - // Allocate and fill cached packet - pkt = malloc( sizeof(tTCPStoredPacket) + dataLen ); - pkt->Next = NULL; - pkt->Sequence = ntohl(Header->SequenceNumber); - pkt->Length = dataLen; - memcpy(pkt->Data, (Uint8*)Header + (Header->DataOffset>>4)*4, dataLen); + sequence_num = ntohl(Header->SequenceNumber); Log_Log("TCP", "0x%08x <= 0x%08x < 0x%08x", Connection->NextSequenceRcv, - pkt->Sequence, + ntohl(Header->SequenceNumber), Connection->NextSequenceRcv + TCP_WINDOW_SIZE ); // Is this packet the next expected packet? - if( pkt->Sequence == Connection->NextSequenceRcv ) + if( sequence_num == Connection->NextSequenceRcv ) { + int rv; // Ooh, Goodie! Add it to the recieved list - TCP_INT_AppendRecieved(Connection, pkt); - free(pkt); + rv = TCP_INT_AppendRecieved(Connection, + (Uint8*)Header + (Header->DataOffset>>4)*4, + dataLen + ); + if(rv != 0) { + break; + } Log_Log("TCP", "0x%08x += %i", Connection->NextSequenceRcv, dataLen); Connection->NextSequenceRcv += dataLen; // 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,9 +458,32 @@ 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, sequence_num, + Connection->NextSequenceRcv+TCP_WINDOW_SIZE, 0xFFFFFFFF) ) { - tTCPStoredPacket *tmp, *prev = NULL; + Uint8 *dataptr = (Uint8*)Header + (Header->DataOffset>>4)*4; + #if CACHE_FUTURE_PACKETS_IN_BYTES + Uint32 index; + int i; + + index = sequence_num % TCP_WINDOW_SIZE; + for( i = 0; i < dataLen; i ++ ) + { + Connection->FuturePacketValidBytes[index/8] |= 1 << (index%8); + Connection->FuturePacketData[index] = dataptr[i]; + // Do a wrap increment + index ++; + if(index == TCP_WINDOW_SIZE) index = 0; + } + #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); @@ -460,16 +516,16 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head } else { - free(pkt); + free(pkt); // TODO: Find some way to remove this } SHORTREL( &Connection->lFuturePackets ); + #endif } // Badly out of sequence packet else { Log_Log("TCP", "Fully out of sequence packet (0x%08x not between 0x%08x and 0x%08x), dropped", - pkt->Sequence, Connection->NextSequenceRcv, Connection->NextSequenceRcv+TCP_WINDOW_SIZE); - free(pkt); + sequence_num, Connection->NextSequenceRcv, Connection->NextSequenceRcv+TCP_WINDOW_SIZE); // TODO: Spec says we should send an empty ACK with the current state } break; @@ -503,7 +559,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 +585,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; @@ -567,27 +623,30 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head /** * \brief Appends a packet to the recieved list * \param Connection Connection structure - * \param Pkt Packet structure on heap + * \param Data Packet contents + * \param Length Length of \a Data */ -void TCP_INT_AppendRecieved(tTCPConnection *Connection, tTCPStoredPacket *Pkt) +int TCP_INT_AppendRecieved(tTCPConnection *Connection, const void *Data, size_t Length) { Mutex_Acquire( &Connection->lRecievedPackets ); - if(Connection->RecievedBuffer->Length + Pkt->Length > Connection->RecievedBuffer->Space ) + + if(Connection->RecievedBuffer->Length + Length > Connection->RecievedBuffer->Space ) { - Log_Error("TCP", "Buffer filled, packet dropped (%s)", - // TCP_INT_DumpConnection(Connection) - "" + VFS_MarkAvaliable(&Connection->Node, 1); + Log_Error("TCP", "Buffer filled, packet dropped (:%i) - %i + %i > %i", + Connection->LocalPort, Connection->RecievedBuffer->Length, Length, + Connection->RecievedBuffer->Space ); - return ; + Mutex_Release( &Connection->lRecievedPackets ); + return 1; } - RingBuffer_Write( Connection->RecievedBuffer, Pkt->Data, Pkt->Length ); + RingBuffer_Write( Connection->RecievedBuffer, Data, Length ); - #if USE_SELECT VFS_MarkAvaliable(&Connection->Node, 1); - #endif Mutex_Release( &Connection->lRecievedPackets ); + return 0; } /** @@ -600,6 +659,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 +763,7 @@ void TCP_INT_UpdateRecievedFromFuture(tTCPConnection *Connection) Connection->NextSequenceRcv += pkt->Length; free(pkt); } + #endif } /** @@ -647,7 +776,7 @@ Uint16 TCP_GetUnusedPort() // Get Next outbound port ret = giTCP_NextOutPort++; - while( gaTCP_PortBitmap[ret/32] & (1 << (ret%32)) ) + while( gaTCP_PortBitmap[ret/32] & (1UL << (ret%32)) ) { ret ++; giTCP_NextOutPort++; @@ -718,10 +847,7 @@ tVFS_Node *TCP_Server_Init(tInterface *Interface) srv->Node.ImplPtr = srv; srv->Node.NumACLs = 1; srv->Node.ACLs = &gVFS_ACL_EveryoneRW; - srv->Node.ReadDir = TCP_Server_ReadDir; - srv->Node.FindDir = TCP_Server_FindDir; - srv->Node.IOCtl = TCP_Server_IOCtl; - srv->Node.Close = TCP_Server_Close; + srv->Node.Type = &gTCP_ServerNodeType; SHORTLOCK(&glTCP_Listeners); srv->Next = gTCP_Listeners; @@ -788,30 +914,43 @@ tVFS_Node *TCP_Server_FindDir(tVFS_Node *Node, const char *Name) int id = atoi(Name); ENTER("pNode sName", Node, Name); - - // Sanity Check - itoa(tmp, id, 16, 8, '0'); - if(strcmp(tmp, Name) != 0) { - LOG("'%s' != '%s' (%08x)", Name, tmp, id); - LEAVE('n'); - return NULL; + + // Check for a non-empty name + if( Name[0] ) + { + // Sanity Check + itoa(tmp, id, 16, 8, '0'); + if(strcmp(tmp, Name) != 0) { + LOG("'%s' != '%s' (%08x)", Name, tmp, id); + LEAVE('n'); + return NULL; + } + + Log_Debug("TCP", "srv->Connections = %p", srv->Connections); + Log_Debug("TCP", "srv->NewConnections = %p", srv->NewConnections); + Log_Debug("TCP", "srv->ConnectionsTail = %p", srv->ConnectionsTail); + + // Search + SHORTLOCK( &srv->lConnections ); + for(conn = srv->Connections; + conn; + conn = conn->Next) + { + LOG("conn->Node.ImplInt = %i", conn->Node.ImplInt); + if(conn->Node.ImplInt == id) break; + } + SHORTREL( &srv->lConnections ); } - - Log_Debug("TCP", "srv->Connections = %p", srv->Connections); - Log_Debug("TCP", "srv->NewConnections = %p", srv->NewConnections); - Log_Debug("TCP", "srv->ConnectionsTail = %p", srv->ConnectionsTail); - - // Search - SHORTLOCK( &srv->lConnections ); - for(conn = srv->Connections; - conn; - conn = conn->Next) + // Empty Name - Check for a new connection and if it's there, open it + else { - LOG("conn->Node.ImplInt = %i", conn->Node.ImplInt); - if(conn->Node.ImplInt == id) break; + SHORTLOCK( &srv->lConnections ); + conn = srv->NewConnections; + if( conn != NULL ) + srv->NewConnections = conn->Next; + SHORTREL( &srv->lConnections ); } - SHORTREL( &srv->lConnections ); - + // If not found, ret NULL if(!conn) { LOG("Connection %i not found", id); @@ -876,23 +1015,29 @@ 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; conn->Node.ACLs = &gVFS_ACL_EveryoneRW; - conn->Node.Read = TCP_Client_Read; - conn->Node.Write = TCP_Client_Write; - conn->Node.IOCtl = TCP_Client_IOCtl; - conn->Node.Close = TCP_Client_Close; + conn->Node.Type = &gTCP_ClientNodeType; 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 +1060,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 +1084,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 ) { @@ -959,7 +1105,7 @@ Uint64 TCP_Client_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buff /** * \brief Send a data packet on a connection */ -void TCP_INT_SendDataPacket(tTCPConnection *Connection, size_t Length, void *Data) +void TCP_INT_SendDataPacket(tTCPConnection *Connection, size_t Length, const void *Data) { char buf[sizeof(tTCPHeader)+Length]; tTCPHeader *packet = (void*)buf; @@ -967,7 +1113,7 @@ void TCP_INT_SendDataPacket(tTCPConnection *Connection, size_t Length, void *Dat packet->SourcePort = htons(Connection->LocalPort); packet->DestPort = htons(Connection->RemotePort); packet->DataOffset = (sizeof(tTCPHeader)/4)*16; - packet->WindowSize = TCP_WINDOW_SIZE; + packet->WindowSize = htons(TCP_WINDOW_SIZE); packet->AcknowlegementNumber = htonl(Connection->NextSequenceRcv); packet->SequenceNumber = htonl(Connection->NextSequenceSend); @@ -976,8 +1122,9 @@ void TCP_INT_SendDataPacket(tTCPConnection *Connection, size_t Length, void *Dat memcpy(packet->Options, Data, Length); Log_Debug("TCP", "Send sequence 0x%08x", Connection->NextSequenceSend); - Debug_HexDump("[TCP ] TCP_INT_SendDataPacket: Data = ", - Data, Length); +#if HEXDUMP_OUTGOING + Debug_HexDump("TCP_INT_SendDataPacket: Data = ", Data, Length); +#endif TCP_SendPacket( Connection, sizeof(tTCPHeader)+Length, packet ); @@ -987,13 +1134,18 @@ void TCP_INT_SendDataPacket(tTCPConnection *Connection, size_t Length, void *Dat /** * \brief Send some bytes on a connection */ -Uint64 TCP_Client_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) +Uint64 TCP_Client_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer) { tTCPConnection *conn = Node->ImplPtr; size_t rem = Length; 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 +1156,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 +1202,7 @@ void TCP_StartConnection(tTCPConnection *Conn) Conn->NextSequenceSend ++; Conn->State = TCP_ST_SYN_SENT; + return ; } @@ -1095,7 +1259,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 +1297,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 +1305,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;