X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Modules%2FIPStack%2Ftcp.c;h=99e6719f30d1f44a77b2e93e2b7483870849c40e;hb=d5834686ad14b66420060192445f06bce85db389;hp=741ec1406e481530fe242c03e8b682ca585b69bd;hpb=54746c855c6e2fe42fde9f93b0ce3f41aeefc2e5;p=tpg%2Facess2.git diff --git a/Modules/IPStack/tcp.c b/Modules/IPStack/tcp.c index 741ec140..99e6719f 100644 --- a/Modules/IPStack/tcp.c +++ b/Modules/IPStack/tcp.c @@ -2,6 +2,7 @@ * Acess2 IP Stack * - TCP Handling */ +#define DEBUG 1 #include "ipstack.h" #include "ipv4.h" #include "tcp.h" @@ -9,6 +10,10 @@ #define TCP_MIN_DYNPORT 0xC000 #define TCP_MAX_HALFOPEN 1024 // Should be enough +#define TCP_MAX_PACKET_SIZE 1024 +#define TCP_WINDOW_SIZE 0x2000 +#define TCP_RECIEVE_BUFFER_SIZE 0x4000 + // === PROTOTYPES === void TCP_Initialise(); void TCP_StartConnection(tTCPConnection *Conn); @@ -23,7 +28,7 @@ Uint16 TCP_GetUnusedPort(); // --- Server tVFS_Node *TCP_Server_Init(tInterface *Interface); char *TCP_Server_ReadDir(tVFS_Node *Node, int Pos); -tVFS_Node *TCP_Server_FindDir(tVFS_Node *Node, char *Name); +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); // --- Client @@ -39,9 +44,9 @@ tSocketFile gTCP_ClientFile = {NULL, "tcpc", TCP_Client_Init}; // === GLOBALS === int giTCP_NumHalfopen = 0; -tSpinlock glTCP_Listeners; +tShortSpinlock glTCP_Listeners; tTCPListener *gTCP_Listeners; -tSpinlock glTCP_OutbountCons; +tShortSpinlock glTCP_OutbountCons; tTCPConnection *gTCP_OutbountCons; Uint32 gaTCP_PortBitmap[0x800]; int giTCP_NextOutPort = TCP_MIN_DYNPORT; @@ -59,28 +64,6 @@ void TCP_Initialise() IPv4_RegisterCallback(IP4PROT_TCP, TCP_GetPacket); } -/** - * \brief Open a connection to another host using TCP - * \param Conn Connection structure - */ -void TCP_StartConnection(tTCPConnection *Conn) -{ - tTCPHeader hdr; - - hdr.SourcePort = Conn->LocalPort; - hdr.DestPort = Conn->RemotePort; - Conn->NextSequenceSend = rand(); - hdr.SequenceNumber = Conn->NextSequenceSend; - hdr.DataOffset = (sizeof(tTCPHeader)/4) << 4; - hdr.Flags = TCP_FLAG_SYN; - hdr.WindowSize = 0; // TODO - hdr.Checksum = 0; // TODO - hdr.UrgentPointer = 0; - - TCP_SendPacket( Conn, sizeof(tTCPHeader), &hdr ); - return ; -} - /** * \brief Sends a packet from the specified connection, calculating the checksums * \param Conn Connection @@ -121,24 +104,36 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe tTCPListener *srv; tTCPConnection *conn; - Log("[TCP ] SourcePort = %i, DestPort = %i", + Log_Log("TCP", "SourcePort = %i, DestPort = %i", ntohs(hdr->SourcePort), ntohs(hdr->DestPort)); - Log("[TCP ] SequenceNumber = 0x%x", ntohl(hdr->SequenceNumber)); - Log("[TCP ] AcknowlegementNumber = 0x%x", ntohl(hdr->AcknowlegementNumber)); - Log("[TCP ] DataOffset = %i", hdr->DataOffset >> 4); - Log("[TCP ] Flags = {"); - Log("[TCP ] CWR = %B, ECE = %B", +/* + Log_Log("TCP", "SequenceNumber = 0x%x", ntohl(hdr->SequenceNumber)); + Log_Log("TCP", "AcknowlegementNumber = 0x%x", ntohl(hdr->AcknowlegementNumber)); + Log_Log("TCP", "DataOffset = %i", hdr->DataOffset >> 4); + Log_Log("TCP", "Flags = {"); + Log_Log("TCP", " CWR = %B, ECE = %B", !!(hdr->Flags & TCP_FLAG_CWR), !!(hdr->Flags & TCP_FLAG_ECE)); - Log("[TCP ] URG = %B, ACK = %B", + Log_Log("TCP", " URG = %B, ACK = %B", !!(hdr->Flags & TCP_FLAG_URG), !!(hdr->Flags & TCP_FLAG_ACK)); - Log("[TCP ] PSH = %B, RST = %B", + Log_Log("TCP", " PSH = %B, RST = %B", !!(hdr->Flags & TCP_FLAG_PSH), !!(hdr->Flags & TCP_FLAG_RST)); - Log("[TCP ] SYN = %B, FIN = %B", + Log_Log("TCP", " SYN = %B, FIN = %B", !!(hdr->Flags & TCP_FLAG_SYN), !!(hdr->Flags & TCP_FLAG_FIN)); - Log("[TCP ] }"); - Log("[TCP ] WindowSize = %i", htons(hdr->WindowSize)); - Log("[TCP ] Checksum = 0x%x", htons(hdr->Checksum)); - Log("[TCP ] UrgentPointer = 0x%x", htons(hdr->UrgentPointer)); + Log_Log("TCP", "}"); + Log_Log("TCP", "WindowSize = %i", htons(hdr->WindowSize)); + Log_Log("TCP", "Checksum = 0x%x", htons(hdr->Checksum)); + Log_Log("TCP", "UrgentPointer = 0x%x", htons(hdr->UrgentPointer)); +*/ + Log_Log("TCP", "Flags = %s%s%s%s%s%s", + (hdr->Flags & TCP_FLAG_CWR) ? "CWR " : "", + (hdr->Flags & TCP_FLAG_ECE) ? "ECE " : "", + (hdr->Flags & TCP_FLAG_URG) ? "URG " : "", + (hdr->Flags & TCP_FLAG_ACK) ? "ACK " : "", + (hdr->Flags & TCP_FLAG_PSH) ? "PSH " : "", + (hdr->Flags & TCP_FLAG_RST) ? "RST " : "", + (hdr->Flags & TCP_FLAG_SYN) ? "SYN " : "", + (hdr->Flags & TCP_FLAG_FIN) ? "FIN " : "" + ); if( Length > (hdr->DataOffset >> 4)*4 ) { @@ -160,17 +155,17 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe // Check the destination port if(srv->Port != htons(hdr->DestPort)) continue; - Log("[TCP ] Matches server %p", srv); + Log_Log("TCP", "Matches server %p", srv); // Is this in an established connection? for( conn = srv->Connections; conn; conn = conn->Next ) { - Log("[TCP ] conn->Interface(%p) == Interface(%p)", + Log_Log("TCP", "conn->Interface(%p) == Interface(%p)", conn->Interface, Interface); // Check that it is coming in on the same interface if(conn->Interface != Interface) continue; // Check Source Port - Log("[TCP ] conn->RemotePort(%i) == hdr->SourcePort(%i)", + Log_Log("TCP", "conn->RemotePort(%i) == hdr->SourcePort(%i)", conn->RemotePort, ntohs(hdr->SourcePort)); if(conn->RemotePort != ntohs(hdr->SourcePort)) continue; @@ -180,17 +175,17 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe if(conn->Interface->Type == 4 && !IP4_EQU(conn->RemoteIP.v4, *(tIPv4*)Address)) continue; - Log("[TCP ] Matches connection %p", conn); + Log_Log("TCP", "Matches connection %p", conn); // We have a response! TCP_INT_HandleConnectionPacket(conn, hdr, Length); return; } - Log("[TCP ] Opening Connection"); + Log_Log("TCP", "Opening Connection"); // Open a new connection (well, check that it's a SYN) if(hdr->Flags != TCP_FLAG_SYN) { - Log("[TCP ] Packet is not a SYN"); + Log_Log("TCP", "Packet is not a SYN"); return ; } @@ -208,12 +203,15 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe case 6: conn->RemoteIP.v6 = *(tIPv6*)Address; break; } + conn->RecievedBuffer = RingBuffer_Create( TCP_RECIEVE_BUFFER_SIZE ); + conn->NextSequenceRcv = ntohl( hdr->SequenceNumber ) + 1; conn->NextSequenceSend = rand(); // Create node conn->Node.NumACLs = 1; 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; @@ -225,7 +223,7 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe // 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 - LOCK(&srv->lConnections); + SHORTLOCK(&srv->lConnections); if( !srv->Connections ) srv->Connections = conn; else @@ -233,7 +231,7 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe srv->ConnectionsTail = conn; if(!srv->NewConnections) srv->NewConnections = conn; - RELEASE(&srv->lConnections); + SHORTLOCK(&srv->lConnections); // Send the SYN ACK hdr->Flags |= TCP_FLAG_ACK; @@ -243,7 +241,7 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe hdr->SourcePort = htons(srv->Port); hdr->DataOffset = (sizeof(tTCPHeader)/4) << 4; TCP_SendPacket( conn, sizeof(tTCPHeader), hdr ); - + conn->NextSequenceSend ++; return ; } } @@ -270,7 +268,7 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe } } - Log("[TCP ] No Match"); + Log_Log("TCP", "No Match"); } /** @@ -284,21 +282,58 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head tTCPStoredPacket *pkt; int dataLen; - Connection->State = TCP_ST_OPEN; if(Header->Flags & TCP_FLAG_SYN) { - Connection->NextSequenceRcv = Header->SequenceNumber + 1; + Connection->NextSequenceRcv = ntohl(Header->SequenceNumber) + 1; + } + + if( Connection->State == TCP_ST_SYN_SENT ) + { + if( (Header->Flags & (TCP_FLAG_SYN|TCP_FLAG_ACK)) == (TCP_FLAG_SYN|TCP_FLAG_ACK) ) { + + 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; + Log_Log("TCP", "ACKing SYN-ACK"); + TCP_SendPacket( Connection, sizeof(tTCPHeader), Header ); + Connection->State = TCP_ST_OPEN; + } } // Get length of data dataLen = Length - (Header->DataOffset>>4)*4; - Log("[TCP ] HandleConnectionPacket - dataLen = %i", dataLen); + Log_Log("TCP", "HandleConnectionPacket - dataLen = %i", dataLen); if(Header->Flags & TCP_FLAG_ACK) { // TODO: Process an ACKed Packet - Log("[TCP ] Conn %p, Packet 0x%x ACKed", Connection, Header->AcknowlegementNumber); + Log_Log("TCP", "Conn %p, Packet 0x%x ACKed", Connection, Header->AcknowlegementNumber); } - if(dataLen == 0) return ; + // TODO: Check what to do here + if(Header->Flags & TCP_FLAG_FIN) { + if( Connection->State == TCP_ST_FIN_SENT ) { + Connection->State = TCP_ST_FINISHED; + return ; + } + else { + Connection->State = TCP_ST_FINISHED; + Header->DestPort = Header->SourcePort; + Header->SourcePort = htons(Connection->LocalPort); + Header->AcknowlegementNumber = htonl(Connection->NextSequenceRcv); + Header->SequenceNumber = htonl(Connection->NextSequenceSend); + Header->Flags = TCP_FLAG_ACK; + TCP_SendPacket( Connection, sizeof(tTCPHeader), Header ); + return ; + } + } + + if(dataLen == 0) { + Log_Log("TCP", "Empty Packet"); + return ; + } // NOTES: // Flags @@ -313,15 +348,16 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head memcpy(pkt->Data, (Uint8*)Header + (Header->DataOffset>>4)*4, dataLen); // Is this packet the next expected packet? + // TODO: Fix this to check if the packet is in the window. if( pkt->Sequence != Connection->NextSequenceRcv ) { tTCPStoredPacket *tmp, *prev = NULL; - Log("[TCP ] Out of sequence packet (0x%08x != 0x%08x)", + Log_Log("TCP", "Out of sequence packet (0x%08x != 0x%08x)", pkt->Sequence, Connection->NextSequenceRcv); // No? Well, let's cache it and look at it later - LOCK( &Connection->lFuturePackets ); + SHORTLOCK( &Connection->lFuturePackets ); for(tmp = Connection->FuturePackets; tmp; prev = tmp, tmp = tmp->Next) @@ -333,29 +369,33 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head else Connection->FuturePackets = pkt; pkt->Next = tmp; - RELEASE( &Connection->lFuturePackets ); + SHORTREL( &Connection->lFuturePackets ); } else { // Ooh, Goodie! Add it to the recieved list TCP_INT_AppendRecieved(Connection, pkt); - if(dataLen) - Connection->NextSequenceRcv += dataLen; - else - Connection->NextSequenceRcv += 1; + free(pkt); + 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. TCP_INT_UpdateRecievedFromFuture(Connection); - } - // TODO: Check ACK code validity - Header->AcknowlegementNumber = ntohl(pkt->Sequence) + dataLen; - Header->SequenceNumber = ntohl(Connection->NextSequenceSend); - Header->Flags &= TCP_FLAG_SYN; - Header->Flags = TCP_FLAG_ACK; - TCP_SendPacket( Connection, sizeof(tTCPHeader), Header ); + // 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, sizeof(tTCPHeader), Header ); + //Connection->NextSequenceSend ++; + } } /** @@ -365,18 +405,19 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head */ void TCP_INT_AppendRecieved(tTCPConnection *Connection, tTCPStoredPacket *Pkt) { - LOCK( &Connection->lRecievedPackets ); - if(Connection->RecievedPackets) - { - Connection->RecievedPacketsTail->Next = Pkt; - Connection->RecievedPacketsTail = Pkt; - } - else + Mutex_Acquire( &Connection->lRecievedPackets ); + if(Connection->RecievedBuffer->Length + Pkt->Length > Connection->RecievedBuffer->Space ) { - Connection->RecievedPackets = Pkt; - Connection->RecievedPacketsTail = Pkt; + Log_Error("TCP", "Buffer filled, packet dropped (%s)", + // TCP_INT_DumpConnection(Connection) + "" + ); + return ; } - RELEASE( &Connection->lRecievedPackets ); + + RingBuffer_Write( Connection->RecievedBuffer, Pkt->Data, Pkt->Length ); + + Mutex_Release( &Connection->lRecievedPackets ); } /** @@ -394,14 +435,14 @@ void TCP_INT_UpdateRecievedFromFuture(tTCPConnection *Connection) { prev = NULL; // Look for the next expected packet in the cache. - LOCK( &Connection->lFuturePackets ); + SHORTLOCK( &Connection->lFuturePackets ); for(pkt = Connection->FuturePackets; pkt && pkt->Sequence < Connection->NextSequenceRcv; prev = pkt, pkt = pkt->Next); // If we can't find the expected next packet, stop looking if(!pkt || pkt->Sequence > Connection->NextSequenceRcv) { - RELEASE( &Connection->lFuturePackets ); + SHORTREL( &Connection->lFuturePackets ); return; } @@ -412,11 +453,12 @@ void TCP_INT_UpdateRecievedFromFuture(tTCPConnection *Connection) Connection->FuturePackets = pkt->Next; // Release list - RELEASE( &Connection->lFuturePackets ); + SHORTREL( &Connection->lFuturePackets ); // Looks like we found one TCP_INT_AppendRecieved(Connection, pkt); - Connection->NextSequenceRcv ++; + Connection->NextSequenceRcv += pkt->Length; + free(pkt); } } @@ -480,12 +522,21 @@ int TCP_DeallocatePort(Uint16 Port) // --- Server tVFS_Node *TCP_Server_Init(tInterface *Interface) { - tTCPListener *srv = malloc( sizeof(tTCPListener) ); + tTCPListener *srv; + + srv = malloc( sizeof(tTCPListener) ); + + if( srv == NULL ) { + Log_Warning("TCP", "malloc failed for listener (%i) bytes", sizeof(tTCPListener)); + return NULL; + } srv->Interface = Interface; srv->Port = 0; srv->NextID = 0; srv->Connections = NULL; + srv->ConnectionsTail = NULL; + srv->NewConnections = NULL; srv->Next = NULL; srv->Node.Flags = VFS_FFLAG_DIRECTORY; srv->Node.Size = -1; @@ -497,10 +548,10 @@ tVFS_Node *TCP_Server_Init(tInterface *Interface) srv->Node.IOCtl = TCP_Server_IOCtl; srv->Node.Close = TCP_Server_Close; - LOCK(&glTCP_Listeners); + SHORTLOCK(&glTCP_Listeners); srv->Next = gTCP_Listeners; gTCP_Listeners = srv; - RELEASE(&glTCP_Listeners); + SHORTREL(&glTCP_Listeners); return &srv->Node; } @@ -516,28 +567,36 @@ char *TCP_Server_ReadDir(tVFS_Node *Node, int Pos) tTCPListener *srv = Node->ImplPtr; tTCPConnection *conn; char *ret; + + ENTER("pNode iPos", Node, Pos); - Log("[TCP ] Thread %i waiting for a connection", Threads_GetTID()); + Log_Log("TCP", "Thread %i waiting for a connection", Threads_GetTID()); for(;;) { - LOCK( &srv->lConnections ); + SHORTLOCK( &srv->lConnections ); if( srv->NewConnections != NULL ) break; - RELEASE( &srv->lConnections ); - Threads_Yield(); + SHORTREL( &srv->lConnections ); + Threads_Yield(); // TODO: Sleep until poked continue; } // Increment the new list (the current connection is still on the - // normal list + // normal list) conn = srv->NewConnections; srv->NewConnections = conn->Next; - RELEASE( &srv->lConnections ); + SHORTREL( &srv->lConnections ); + + LOG("conn = %p", conn); + LOG("srv->Connections = %p", srv->Connections); + LOG("srv->NewConnections = %p", srv->NewConnections); + LOG("srv->ConnectionsTail = %p", srv->ConnectionsTail); ret = malloc(9); - itoa(ret, Node->ImplInt, 16, 8, '0'); - Log("TCP_Server_ReadDir: RETURN '%s'", ret); + itoa(ret, conn->Node.ImplInt, 16, 8, '0'); + Log_Log("TCP", "Thread %i got '%s'", Threads_GetTID(), ret); + LEAVE('s', ret); return ret; } @@ -546,28 +605,47 @@ char *TCP_Server_ReadDir(tVFS_Node *Node, int Pos) * \param Node Server node * \param Name Hexadecimal ID of the node */ -tVFS_Node *TCP_Server_FindDir(tVFS_Node *Node, char *Name) +tVFS_Node *TCP_Server_FindDir(tVFS_Node *Node, const char *Name) { tTCPConnection *conn; tTCPListener *srv = Node->ImplPtr; char tmp[9]; int id = atoi(Name); + ENTER("pNode sName", Node, Name); + // Sanity Check itoa(tmp, id, 16, 8, '0'); - if(strcmp(tmp, Name) != 0) return NULL; + 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 - LOCK( &srv->lConnections ); + SHORTLOCK( &srv->lConnections ); for(conn = srv->Connections; - conn && conn->Node.ImplInt != id; - conn = conn->Next); - RELEASE( &srv->lConnections ); + conn; + conn = conn->Next) + { + LOG("conn->Node.ImplInt = %i", conn->Node.ImplInt); + if(conn->Node.ImplInt == id) break; + } + SHORTREL( &srv->lConnections ); // If not found, ret NULL - if(!conn) return NULL; + if(!conn) { + LOG("Connection %i not found", id); + LEAVE('n'); + return NULL; + } // Return node + LEAVE('p', &conn->Node); return &conn->Node; } @@ -605,7 +683,7 @@ int TCP_Server_IOCtl(tVFS_Node *Node, int ID, void *Data) else // Else, mark this as used TCP_AllocatePort(srv->Port); - Log("[TCP ] Server %p listening on port %i", srv, srv->Port); + Log_Log("TCP", "Server %p listening on port %i", srv, srv->Port); return srv->Port; } @@ -627,8 +705,8 @@ tVFS_Node *TCP_Client_Init(tInterface *Interface) conn->State = TCP_ST_CLOSED; conn->Interface = Interface; - conn->LocalPort = 0; - conn->RemotePort = 0; + conn->LocalPort = -1; + conn->RemotePort = -1; memset( &conn->RemoteIP, 0, sizeof(conn->RemoteIP) ); conn->Node.ImplPtr = conn; @@ -639,10 +717,12 @@ tVFS_Node *TCP_Client_Init(tInterface *Interface) conn->Node.IOCtl = TCP_Client_IOCtl; conn->Node.Close = TCP_Client_Close; - LOCK(&glTCP_OutbountCons); + conn->RecievedBuffer = RingBuffer_Create( TCP_RECIEVE_BUFFER_SIZE ); + + SHORTLOCK(&glTCP_OutbountCons); conn->Next = gTCP_OutbountCons; gTCP_OutbountCons = conn; - RELEASE(&glTCP_OutbountCons); + SHORTREL(&glTCP_OutbountCons); return &conn->Node; } @@ -655,46 +735,122 @@ tVFS_Node *TCP_Client_Init(tInterface *Interface) Uint64 TCP_Client_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) { tTCPConnection *conn = Node->ImplPtr; - tTCPStoredPacket *pkt; + char *destbuf = Buffer; + size_t len; - Log("TCP_Client_Read: (Length=%i)", Length); + ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer); + LOG("conn = %p", conn); + LOG("conn->State = %i", conn->State); // Check if connection is open - if( conn->State != TCP_ST_OPEN ) return 0; + while( conn->State == TCP_ST_HALFOPEN || conn->State == TCP_ST_SYN_SENT ) + Threads_Yield(); + if( conn->State != TCP_ST_OPEN ) { + LEAVE('i', 0); + return 0; + } // Poll packets for(;;) - { + { // Lock list and check if there is a packet - LOCK( &conn->lRecievedPackets ); - if( conn->RecievedPackets == NULL ) { + Mutex_Acquire( &conn->lRecievedPackets ); + if( conn->RecievedBuffer->Length == 0 ) { // If not, release the lock, yield and try again - RELEASE( &conn->lRecievedPackets ); - Threads_Yield(); + Mutex_Release( &conn->lRecievedPackets ); + Threads_Yield(); // TODO: Less expensive wait continue; } - // Get packet pointer - pkt = conn->RecievedPackets; - conn->RecievedPackets = pkt->Next; - // Release the lock (we don't need it any more) - RELEASE( &conn->lRecievedPackets ); - - Log("TCP_Client_Read: pkt->Length = %i", pkt->Length); - - // Copy Data - if(Length > pkt->Length) Length = pkt->Length; - memcpy(Buffer, pkt->Data, Length); + // Attempt to read all `Length` bytes + len = RingBuffer_Read( destbuf, conn->RecievedBuffer, Length ); - // Free packet and return - free(pkt); - return Length; + // Release the lock (we don't need it any more) + Mutex_Release( &conn->lRecievedPackets ); + + LEAVE('i', len); + return len; } } +/** + * \brief Send a data packet on a connection + */ +void TCP_INT_SendDataPacket(tTCPConnection *Connection, size_t Length, void *Data) +{ + char buf[sizeof(tTCPHeader)+Length]; + tTCPHeader *packet = (void*)buf; + + packet->SourcePort = htons(Connection->LocalPort); + packet->DestPort = htons(Connection->RemotePort); + packet->DataOffset = (sizeof(tTCPHeader)/4)*16; + packet->WindowSize = TCP_WINDOW_SIZE; + + packet->AcknowlegementNumber = htonl(Connection->NextSequenceRcv); + packet->SequenceNumber = htonl(Connection->NextSequenceSend); + packet->Flags = TCP_FLAG_PSH|TCP_FLAG_ACK; // Hey, ACK if you can! + + memcpy(packet->Options, Data, Length); + + TCP_SendPacket( Connection, sizeof(tTCPHeader)+Length, packet ); + + Connection->NextSequenceSend += Length; +} + +/** + * \brief Send some bytes on a connection + */ Uint64 TCP_Client_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) { - return 0; + tTCPConnection *conn = Node->ImplPtr; + size_t rem = Length; + + ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer); + + // Check if connection is open + while( conn->State == TCP_ST_HALFOPEN || conn->State == TCP_ST_SYN_SENT ) + Threads_Yield(); + if( conn->State != TCP_ST_OPEN ) { + LEAVE('i', 0); + return 0; + } + + while( rem > TCP_MAX_PACKET_SIZE ) + { + TCP_INT_SendDataPacket(conn, TCP_MAX_PACKET_SIZE, Buffer); + Buffer += TCP_MAX_PACKET_SIZE; + } + + TCP_INT_SendDataPacket(conn, rem, Buffer); + + LEAVE('i', Length); + return Length; +} + +/** + * \brief Open a connection to another host using TCP + * \param Conn Connection structure + */ +void TCP_StartConnection(tTCPConnection *Conn) +{ + tTCPHeader hdr = {0}; + + Conn->State = TCP_ST_SYN_SENT; + + hdr.SourcePort = htons(Conn->LocalPort); + hdr.DestPort = htons(Conn->RemotePort); + Conn->NextSequenceSend = rand(); + hdr.SequenceNumber = htonl(Conn->NextSequenceSend); + hdr.DataOffset = (sizeof(tTCPHeader)/4) << 4; + hdr.Flags = TCP_FLAG_SYN; + hdr.WindowSize = htons(TCP_WINDOW_SIZE); // Max + hdr.Checksum = 0; // TODO + + TCP_SendPacket( Conn, sizeof(tTCPHeader), &hdr ); + + Conn->NextSequenceSend ++; + Conn->State = TCP_ST_SYN_SENT; + return ; } /** @@ -725,7 +881,7 @@ int TCP_Client_IOCtl(tVFS_Node *Node, int ID, void *Data) if(conn->State != TCP_ST_CLOSED) return -1; if(!CheckMem(Data, sizeof(Uint16))) return -1; conn->RemotePort = *(Uint16*)Data; - return 0; + return conn->RemotePort; case 6: // Set Remote IP if( conn->State != TCP_ST_CLOSED ) @@ -743,13 +899,17 @@ int TCP_Client_IOCtl(tVFS_Node *Node, int ID, void *Data) return 0; case 7: // Connect - if(conn->LocalPort == -1) + if(conn->LocalPort == 0xFFFF) conn->LocalPort = TCP_GetUnusedPort(); if(conn->RemotePort == -1) return 0; TCP_StartConnection(conn); return 1; + + // Get recieve buffer length + case 8: + return conn->RecievedBuffer->Length; } return 0; @@ -757,5 +917,23 @@ int TCP_Client_IOCtl(tVFS_Node *Node, int ID, void *Data) void TCP_Client_Close(tVFS_Node *Node) { - free(Node->ImplPtr); + tTCPConnection *conn = Node->ImplPtr; + tTCPHeader packet; + + packet.SourcePort = htons(conn->LocalPort); + packet.DestPort = htons(conn->RemotePort); + packet.DataOffset = (sizeof(tTCPHeader)/4)*16; + packet.WindowSize = TCP_WINDOW_SIZE; + + packet.AcknowlegementNumber = 0; + packet.SequenceNumber = htonl(conn->NextSequenceSend); + packet.Flags = TCP_FLAG_FIN; + + conn->State = TCP_ST_FIN_SENT; + + TCP_SendPacket( conn, sizeof(tTCPHeader), &packet ); + + while( conn->State == TCP_ST_FIN_SENT ) Threads_Yield(); + + free(conn); }