90f3dc9663d9fe62cb8abe7720fbc5d050203ef0
[tpg/acess2.git] / Modules / IPStack / tcp.c
1 /*
2  * Acess2 IP Stack
3  * - TCP Handling
4  */
5 #define DEBUG   1
6 #include "ipstack.h"
7 #include "ipv4.h"
8 #include "tcp.h"
9
10 #define TCP_MIN_DYNPORT 0xC000
11 #define TCP_MAX_HALFOPEN        1024    // Should be enough
12
13 #define TCP_MAX_PACKET_SIZE     1024
14 #define TCP_WINDOW_SIZE 0x2000
15 #define TCP_RECIEVE_BUFFER_SIZE 0x4000
16
17 // === PROTOTYPES ===
18 void    TCP_Initialise();
19 void    TCP_StartConnection(tTCPConnection *Conn);
20 void    TCP_SendPacket(tTCPConnection *Conn, size_t Length, tTCPHeader *Data);
21 void    TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer);
22 void    TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Header, int Length);
23 void    TCP_INT_AppendRecieved(tTCPConnection *Connection, tTCPStoredPacket *Ptk);
24 void    TCP_INT_UpdateRecievedFromFuture(tTCPConnection *Connection);
25 Uint16  TCP_GetUnusedPort();
26  int    TCP_AllocatePort(Uint16 Port);
27  int    TCP_DeallocatePort(Uint16 Port);
28 // --- Server
29 tVFS_Node       *TCP_Server_Init(tInterface *Interface);
30 char    *TCP_Server_ReadDir(tVFS_Node *Node, int Pos);
31 tVFS_Node       *TCP_Server_FindDir(tVFS_Node *Node, char *Name);
32  int    TCP_Server_IOCtl(tVFS_Node *Node, int ID, void *Data);
33 void    TCP_Server_Close(tVFS_Node *Node);
34 // --- Client
35 tVFS_Node       *TCP_Client_Init(tInterface *Interface);
36 Uint64  TCP_Client_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
37 Uint64  TCP_Client_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
38  int    TCP_Client_IOCtl(tVFS_Node *Node, int ID, void *Data);
39 void    TCP_Client_Close(tVFS_Node *Node);
40
41 // === TEMPLATES ===
42 tSocketFile     gTCP_ServerFile = {NULL, "tcps", TCP_Server_Init};
43 tSocketFile     gTCP_ClientFile = {NULL, "tcpc", TCP_Client_Init};
44
45 // === GLOBALS ===
46  int    giTCP_NumHalfopen = 0;
47 tSpinlock       glTCP_Listeners;
48 tTCPListener    *gTCP_Listeners;
49 tSpinlock       glTCP_OutbountCons;
50 tTCPConnection  *gTCP_OutbountCons;
51 Uint32  gaTCP_PortBitmap[0x800];
52  int    giTCP_NextOutPort = TCP_MIN_DYNPORT;
53
54 // === CODE ===
55 /**
56  * \brief Initialise the TCP Layer
57  * 
58  * Registers the client and server files and the GetPacket callback
59  */
60 void TCP_Initialise()
61 {
62         IPStack_AddFile(&gTCP_ServerFile);
63         IPStack_AddFile(&gTCP_ClientFile);
64         IPv4_RegisterCallback(IP4PROT_TCP, TCP_GetPacket);
65 }
66
67 /**
68  * \brief Sends a packet from the specified connection, calculating the checksums
69  * \param Conn  Connection
70  * \param Length        Length of data
71  * \param Data  Packet data (cast as a TCP Header)
72  */
73 void TCP_SendPacket( tTCPConnection *Conn, size_t Length, tTCPHeader *Data )
74 {
75         size_t  buflen;
76         Uint32  *buf;
77         switch( Conn->Interface->Type )
78         {
79         case 4: // Append IPv4 Pseudo Header
80                 buflen = 4 + 4 + 4 + ((Length+1)&~1);
81                 buf = malloc( buflen );
82                 buf[0] = Conn->Interface->IP4.Address.L;
83                 buf[1] = Conn->RemoteIP.v4.L;
84                 buf[2] = (htons(Length)<<16) | (6<<8) | 0;
85                 Data->Checksum = 0;
86                 memcpy( &buf[3], Data, Length );
87                 Data->Checksum = IPv4_Checksum( buf, buflen );
88                 free(buf);
89                 IPv4_SendPacket(Conn->Interface, Conn->RemoteIP.v4, IP4PROT_TCP, 0, Length, Data);
90                 break;
91         }
92 }
93
94 /**
95  * \brief Handles a packet from the IP Layer
96  * \param Interface     Interface the packet arrived from
97  * \param Address       Pointer to the addres structure
98  * \param Length        Size of packet in bytes
99  * \param Buffer        Packet data
100  */
101 void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer)
102 {
103         tTCPHeader      *hdr = Buffer;
104         tTCPListener    *srv;
105         tTCPConnection  *conn;
106
107         Log_Log("TCP", "SourcePort = %i, DestPort = %i",
108                 ntohs(hdr->SourcePort), ntohs(hdr->DestPort));
109 /*
110         Log_Log("TCP", "SequenceNumber = 0x%x", ntohl(hdr->SequenceNumber));
111         Log_Log("TCP", "AcknowlegementNumber = 0x%x", ntohl(hdr->AcknowlegementNumber));
112         Log_Log("TCP", "DataOffset = %i", hdr->DataOffset >> 4);
113         Log_Log("TCP", "Flags = {");
114         Log_Log("TCP", "  CWR = %B, ECE = %B",
115                 !!(hdr->Flags & TCP_FLAG_CWR), !!(hdr->Flags & TCP_FLAG_ECE));
116         Log_Log("TCP", "  URG = %B, ACK = %B",
117                 !!(hdr->Flags & TCP_FLAG_URG), !!(hdr->Flags & TCP_FLAG_ACK));
118         Log_Log("TCP", "  PSH = %B, RST = %B",
119                 !!(hdr->Flags & TCP_FLAG_PSH), !!(hdr->Flags & TCP_FLAG_RST));
120         Log_Log("TCP", "  SYN = %B, FIN = %B",
121                 !!(hdr->Flags & TCP_FLAG_SYN), !!(hdr->Flags & TCP_FLAG_FIN));
122         Log_Log("TCP", "}");
123         Log_Log("TCP", "WindowSize = %i", htons(hdr->WindowSize));
124         Log_Log("TCP", "Checksum = 0x%x", htons(hdr->Checksum));
125         Log_Log("TCP", "UrgentPointer = 0x%x", htons(hdr->UrgentPointer));
126 */
127
128         if( Length > (hdr->DataOffset >> 4)*4 )
129         {
130                 Debug_HexDump(
131                         "[TCP  ] Packet Data = ",
132                         (Uint8*)hdr + (hdr->DataOffset >> 4)*4,
133                         Length - (hdr->DataOffset >> 4)*4
134                         );
135         }
136
137         // Check Servers
138         {
139                 for( srv = gTCP_Listeners; srv; srv = srv->Next )
140                 {
141                         // Check if the server is active
142                         if(srv->Port == 0)      continue;
143                         // Check the interface
144                         if(srv->Interface && srv->Interface != Interface)       continue;
145                         // Check the destination port
146                         if(srv->Port != htons(hdr->DestPort))   continue;
147                         
148                         Log_Log("TCP", "Matches server %p", srv);
149                         // Is this in an established connection?
150                         for( conn = srv->Connections; conn; conn = conn->Next )
151                         {
152                                 Log_Log("TCP", "conn->Interface(%p) == Interface(%p)",
153                                         conn->Interface, Interface);
154                                 // Check that it is coming in on the same interface
155                                 if(conn->Interface != Interface)        continue;
156
157                                 // Check Source Port
158                                 Log_Log("TCP", "conn->RemotePort(%i) == hdr->SourcePort(%i)",
159                                         conn->RemotePort, ntohs(hdr->SourcePort));
160                                 if(conn->RemotePort != ntohs(hdr->SourcePort))  continue;
161
162                                 // Check Source IP
163                                 if(conn->Interface->Type == 6 && !IP6_EQU(conn->RemoteIP.v6, *(tIPv6*)Address))
164                                         continue;
165                                 if(conn->Interface->Type == 4 && !IP4_EQU(conn->RemoteIP.v4, *(tIPv4*)Address))
166                                         continue;
167
168                                 Log_Log("TCP", "Matches connection %p", conn);
169                                 // We have a response!
170                                 TCP_INT_HandleConnectionPacket(conn, hdr, Length);
171
172                                 return;
173                         }
174
175                         Log_Log("TCP", "Opening Connection");
176                         // Open a new connection (well, check that it's a SYN)
177                         if(hdr->Flags != TCP_FLAG_SYN) {
178                                 Log_Log("TCP", "Packet is not a SYN");
179                                 return ;
180                         }
181                         
182                         // TODO: Check for halfopen max
183                         
184                         conn = calloc(1, sizeof(tTCPConnection));
185                         conn->State = TCP_ST_HALFOPEN;
186                         conn->LocalPort = srv->Port;
187                         conn->RemotePort = ntohs(hdr->SourcePort);
188                         conn->Interface = Interface;
189                         
190                         switch(Interface->Type)
191                         {
192                         case 4: conn->RemoteIP.v4 = *(tIPv4*)Address;   break;
193                         case 6: conn->RemoteIP.v6 = *(tIPv6*)Address;   break;
194                         }
195                         
196                         conn->RecievedBuffer = RingBuffer_Create( TCP_RECIEVE_BUFFER_SIZE );
197                         
198                         conn->NextSequenceRcv = ntohl( hdr->SequenceNumber ) + 1;
199                         conn->NextSequenceSend = rand();
200                         
201                         // Create node
202                         conn->Node.NumACLs = 1;
203                         conn->Node.ACLs = &gVFS_ACL_EveryoneRW;
204                         conn->Node.ImplPtr = conn;
205                         conn->Node.ImplInt = srv->NextID ++;
206                         conn->Node.Read = TCP_Client_Read;
207                         conn->Node.Write = TCP_Client_Write;
208                         //conn->Node.Close = TCP_SrvConn_Close;
209                         
210                         // Hmm... Theoretically, this lock will never have to wait,
211                         // as the interface is locked to the watching thread, and this
212                         // runs in the watching thread. But, it's a good idea to have
213                         // it, just in case
214                         // Oh, wait, there is a case where a wildcard can be used
215                         // (srv->Interface == NULL) so having the lock is a good idea
216                         LOCK(&srv->lConnections);
217                         if( !srv->Connections )
218                                 srv->Connections = conn;
219                         else
220                                 srv->ConnectionsTail->Next = conn;
221                         srv->ConnectionsTail = conn;
222                         if(!srv->NewConnections)
223                                 srv->NewConnections = conn;
224                         RELEASE(&srv->lConnections);
225
226                         // Send the SYN ACK
227                         hdr->Flags |= TCP_FLAG_ACK;
228                         hdr->AcknowlegementNumber = htonl(conn->NextSequenceRcv);
229                         hdr->SequenceNumber = htonl(conn->NextSequenceSend);
230                         hdr->DestPort = hdr->SourcePort;
231                         hdr->SourcePort = htons(srv->Port);
232                         hdr->DataOffset = (sizeof(tTCPHeader)/4) << 4;
233                         TCP_SendPacket( conn, sizeof(tTCPHeader), hdr );
234                         conn->NextSequenceSend ++;
235                         return ;
236                 }
237         }
238
239
240         // Check Open Connections
241         {
242                 for( conn = gTCP_OutbountCons; conn; conn = conn->Next )
243                 {
244                         // Check that it is coming in on the same interface
245                         if(conn->Interface != Interface)        continue;
246
247                         // Check Source Port
248                         if(conn->RemotePort != ntohs(hdr->SourcePort))  continue;
249
250                         // Check Source IP
251                         if(conn->Interface->Type == 6 && !IP6_EQU(conn->RemoteIP.v6, *(tIPv6*)Address))
252                                 continue;
253                         if(conn->Interface->Type == 4 && !IP4_EQU(conn->RemoteIP.v4, *(tIPv4*)Address))
254                                 continue;
255
256                         TCP_INT_HandleConnectionPacket(conn, hdr, Length);
257                         return ;
258                 }
259         }
260         
261         Log_Log("TCP", "No Match");
262 }
263
264 /**
265  * \brief Handles a packet sent to a specific connection
266  * \param Connection    TCP Connection pointer
267  * \param Header        TCP Packet pointer
268  * \param Length        Length of the packet
269  */
270 void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Header, int Length)
271 {       
272         tTCPStoredPacket        *pkt;
273          int    dataLen;
274         
275         if(Header->Flags & TCP_FLAG_SYN) {
276                 Connection->NextSequenceRcv = ntohl(Header->SequenceNumber) + 1;
277         }
278         
279         if( Connection->State == TCP_ST_SYN_SENT )
280         {
281                 if( (Header->Flags & (TCP_FLAG_SYN|TCP_FLAG_ACK)) == (TCP_FLAG_SYN|TCP_FLAG_ACK) ) {
282                         
283                         Header->DestPort = Header->SourcePort;
284                         Header->SourcePort = htons(Connection->LocalPort);
285                         Header->AcknowlegementNumber = htonl(Connection->NextSequenceRcv);
286                         Header->SequenceNumber = htonl(Connection->NextSequenceSend);
287                         Header->WindowSize = htons(TCP_WINDOW_SIZE);
288                         Header->Flags = TCP_FLAG_ACK;
289                         Header->DataOffset = (sizeof(tTCPHeader)/4) << 4;
290                         Log_Log("TCP", "ACKing SYN-ACK");
291                         TCP_SendPacket( Connection, sizeof(tTCPHeader), Header );
292                         Connection->State = TCP_ST_OPEN;
293                 }
294         }
295         
296         // Get length of data
297         dataLen = Length - (Header->DataOffset>>4)*4;
298         Log_Log("TCP", "HandleConnectionPacket - dataLen = %i", dataLen);
299         
300         if(Header->Flags & TCP_FLAG_ACK) {
301                 // TODO: Process an ACKed Packet
302                 Log_Log("TCP", "Conn %p, Packet 0x%x ACKed", Connection, Header->AcknowlegementNumber);
303         }
304         
305         // TODO: Check what to do here
306         if(Header->Flags & TCP_FLAG_FIN) {
307                 if( Connection->State == TCP_ST_FIN_SENT ) {
308                         Connection->State = TCP_ST_FINISHED;
309                         return ;
310                 }
311                 else {
312                         Connection->State = TCP_ST_FINISHED;
313                         Header->DestPort = Header->SourcePort;
314                         Header->SourcePort = htons(Connection->LocalPort);
315                         Header->AcknowlegementNumber = htonl(Connection->NextSequenceRcv);
316                         Header->SequenceNumber = htonl(Connection->NextSequenceSend);
317                         Header->Flags = TCP_FLAG_ACK;
318                         TCP_SendPacket( Connection, sizeof(tTCPHeader), Header );
319                         return ;
320                 }
321         }
322         
323         if(dataLen == 0) {
324                 Log_Log("TCP", "Empty Packet");
325                 return ;
326         }
327         
328         // NOTES:
329         // Flags
330         //    PSH - Has Data?
331         // /NOTES
332         
333         // Allocate and fill cached packet
334         pkt = malloc( dataLen + sizeof(tTCPStoredPacket) );
335         pkt->Next = NULL;
336         pkt->Sequence = ntohl(Header->SequenceNumber);
337         pkt->Length = dataLen;
338         memcpy(pkt->Data, (Uint8*)Header + (Header->DataOffset>>4)*4, dataLen);
339         
340         // Is this packet the next expected packet?
341         // TODO: Fix this to check if the packet is in the window.
342         if( pkt->Sequence != Connection->NextSequenceRcv )
343         {
344                 tTCPStoredPacket        *tmp, *prev = NULL;
345                 
346                 Log_Log("TCP", "Out of sequence packet (0x%08x != 0x%08x)",
347                         pkt->Sequence, Connection->NextSequenceRcv);
348                 
349                 // No? Well, let's cache it and look at it later
350                 LOCK( &Connection->lFuturePackets );
351                 for(tmp = Connection->FuturePackets;
352                         tmp;
353                         prev = tmp, tmp = tmp->Next)
354                 {
355                         if(tmp->Sequence > pkt->Sequence)       break;
356                 }
357                 if(prev)
358                         prev->Next = pkt;
359                 else
360                         Connection->FuturePackets = pkt;
361                 pkt->Next = tmp;
362                 RELEASE( &Connection->lFuturePackets );
363         }
364         else
365         {
366                 // Ooh, Goodie! Add it to the recieved list
367                 TCP_INT_AppendRecieved(Connection, pkt);
368                 free(pkt);
369                 Log_Log("TCP", "0x%08x += %i", Connection->NextSequenceRcv, dataLen);
370                 Connection->NextSequenceRcv += dataLen;
371                 
372                 // TODO: This should be moved out of the watcher thread,
373                 // so that a single lost packet on one connection doesn't cause
374                 // all connections on the interface to lag.
375                 TCP_INT_UpdateRecievedFromFuture(Connection);
376         
377                 // ACK Packet
378                 Header->DestPort = Header->SourcePort;
379                 Header->SourcePort = htons(Connection->LocalPort);
380                 Header->AcknowlegementNumber = htonl(Connection->NextSequenceRcv);
381                 Header->SequenceNumber = htonl(Connection->NextSequenceSend);
382                 Header->WindowSize = htons(TCP_WINDOW_SIZE);
383                 Header->Flags &= TCP_FLAG_SYN;  // Eliminate all flags save for SYN
384                 Header->Flags |= TCP_FLAG_ACK;  // Add ACK
385                 Log_Log("TCP", "Sending ACK for 0x%08x", Connection->NextSequenceRcv);
386                 TCP_SendPacket( Connection, sizeof(tTCPHeader), Header );
387                 //Connection->NextSequenceSend ++;
388         }
389 }
390
391 /**
392  * \brief Appends a packet to the recieved list
393  * \param Connection    Connection structure
394  * \param Pkt   Packet structure on heap
395  */
396 void TCP_INT_AppendRecieved(tTCPConnection *Connection, tTCPStoredPacket *Pkt)
397 {
398         LOCK( &Connection->lRecievedPackets );
399         if(Connection->RecievedBuffer->Length + Pkt->Length > Connection->RecievedBuffer->Space )
400         {
401                 Log_Error("TCP", "Buffer filled, packet dropped (%s)",
402                 //      TCP_INT_DumpConnection(Connection)
403                         ""
404                         );
405                 return ;
406         }
407         
408         RingBuffer_Write( Connection->RecievedBuffer, Pkt->Data, Pkt->Length );
409         
410         RELEASE( &Connection->lRecievedPackets );
411 }
412
413 /**
414  * \brief Updates the connections recieved list from the future list
415  * \param Connection    Connection structure
416  * 
417  * Updates the recieved packets list with packets from the future (out 
418  * of order) packets list that are now able to be added in direct
419  * sequence.
420  */
421 void TCP_INT_UpdateRecievedFromFuture(tTCPConnection *Connection)
422 {
423         tTCPStoredPacket        *pkt, *prev;
424         for(;;)
425         {
426                 prev = NULL;
427                 // Look for the next expected packet in the cache.
428                 LOCK( &Connection->lFuturePackets );
429                 for(pkt = Connection->FuturePackets;
430                         pkt && pkt->Sequence < Connection->NextSequenceRcv;
431                         prev = pkt, pkt = pkt->Next);
432                 
433                 // If we can't find the expected next packet, stop looking
434                 if(!pkt || pkt->Sequence > Connection->NextSequenceRcv) {
435                         RELEASE( &Connection->lFuturePackets );
436                         return;
437                 }
438                 
439                 // Delete packet from future list
440                 if(prev)
441                         prev->Next = pkt->Next;
442                 else
443                         Connection->FuturePackets = pkt->Next;
444                 
445                 // Release list
446                 RELEASE( &Connection->lFuturePackets );
447                 
448                 // Looks like we found one
449                 TCP_INT_AppendRecieved(Connection, pkt);
450                 Connection->NextSequenceRcv += pkt->Length;
451                 free(pkt);
452         }
453 }
454
455 /**
456  * \fn Uint16 TCP_GetUnusedPort()
457  * \brief Gets an unused port and allocates it
458  */
459 Uint16 TCP_GetUnusedPort()
460 {
461         Uint16  ret;
462
463         // Get Next outbound port
464         ret = giTCP_NextOutPort++;
465         while( gaTCP_PortBitmap[ret/32] & (1 << (ret%32)) )
466         {
467                 ret ++;
468                 giTCP_NextOutPort++;
469                 if(giTCP_NextOutPort == 0x10000) {
470                         ret = giTCP_NextOutPort = TCP_MIN_DYNPORT;
471                 }
472         }
473
474         // Mark the new port as used
475         gaTCP_PortBitmap[ret/32] |= 1 << (ret%32);
476
477         return ret;
478 }
479
480 /**
481  * \fn int TCP_AllocatePort(Uint16 Port)
482  * \brief Marks a port as used
483  */
484 int TCP_AllocatePort(Uint16 Port)
485 {
486         // Check if the port has already been allocated
487         if( gaTCP_PortBitmap[Port/32] & (1 << (Port%32)) )
488                 return 0;
489
490         // Allocate
491         gaTCP_PortBitmap[Port/32] |= 1 << (Port%32);
492
493         return 1;
494 }
495
496 /**
497  * \fn int TCP_DeallocatePort(Uint16 Port)
498  * \brief Marks a port as unused
499  */
500 int TCP_DeallocatePort(Uint16 Port)
501 {
502         // Check if the port has already been allocated
503         if( !(gaTCP_PortBitmap[Port/32] & (1 << (Port%32))) )
504                 return 0;
505
506         // Allocate
507         gaTCP_PortBitmap[Port/32] &= ~(1 << (Port%32));
508
509         return 1;
510 }
511
512 // --- Server
513 tVFS_Node *TCP_Server_Init(tInterface *Interface)
514 {
515         tTCPListener    *srv;
516         
517         srv = malloc( sizeof(tTCPListener) );
518
519         if( srv == NULL ) {
520                 Log_Warning("TCP", "malloc failed for listener (%i) bytes", sizeof(tTCPListener));
521                 return NULL;
522         }
523
524         srv->Interface = Interface;
525         srv->Port = 0;
526         srv->NextID = 0;
527         srv->Connections = NULL;
528         srv->ConnectionsTail = NULL;
529         srv->NewConnections = NULL;
530         srv->Next = NULL;
531         srv->Node.Flags = VFS_FFLAG_DIRECTORY;
532         srv->Node.Size = -1;
533         srv->Node.ImplPtr = srv;
534         srv->Node.NumACLs = 1;
535         srv->Node.ACLs = &gVFS_ACL_EveryoneRW;
536         srv->Node.ReadDir = TCP_Server_ReadDir;
537         srv->Node.FindDir = TCP_Server_FindDir;
538         srv->Node.IOCtl = TCP_Server_IOCtl;
539         srv->Node.Close = TCP_Server_Close;
540
541         LOCK(&glTCP_Listeners);
542         srv->Next = gTCP_Listeners;
543         gTCP_Listeners = srv;
544         RELEASE(&glTCP_Listeners);
545
546         return &srv->Node;
547 }
548
549 /**
550  * \brief Wait for a new connection and return the connection ID
551  * \note Blocks until a new connection is made
552  * \param Node  Server node
553  * \param Pos   Position (ignored)
554  */
555 char *TCP_Server_ReadDir(tVFS_Node *Node, int Pos)
556 {
557         tTCPListener    *srv = Node->ImplPtr;
558         tTCPConnection  *conn;
559         char    *ret;
560         
561         ENTER("pNode iPos", Node, Pos);
562
563         Log_Log("TCP", "Thread %i waiting for a connection", Threads_GetTID());
564         for(;;)
565         {
566                 LOCK( &srv->lConnections );
567                 if( srv->NewConnections != NULL )       break;
568                 RELEASE( &srv->lConnections );
569                 Threads_Yield();
570                 continue;
571         }
572         
573
574         // Increment the new list (the current connection is still on the 
575         // normal list)
576         conn = srv->NewConnections;
577         srv->NewConnections = conn->Next;
578         
579         LOG("conn = %p", conn);
580         LOG("srv->Connections = %p", srv->Connections);
581         LOG("srv->NewConnections = %p", srv->NewConnections);
582         LOG("srv->ConnectionsTail = %p", srv->ConnectionsTail);
583         
584         RELEASE( &srv->lConnections );
585
586         ret = malloc(9);
587         itoa(ret, conn->Node.ImplInt, 16, 8, '0');
588         Log_Log("TCP", "Thread %i got '%s'", Threads_GetTID(), ret);
589         LEAVE('s', ret);
590         return ret;
591 }
592
593 /**
594  * \brief Gets a client connection node
595  * \param Node  Server node
596  * \param Name  Hexadecimal ID of the node
597  */
598 tVFS_Node *TCP_Server_FindDir(tVFS_Node *Node, char *Name)
599 {
600         tTCPConnection  *conn;
601         tTCPListener    *srv = Node->ImplPtr;
602         char    tmp[9];
603          int    id = atoi(Name);
604         
605         ENTER("pNode sName", Node, Name);
606         
607         // Sanity Check
608         itoa(tmp, id, 16, 8, '0');
609         if(strcmp(tmp, Name) != 0) {
610                 LOG("'%s' != '%s' (%08x)", Name, tmp, id);
611                 LEAVE('n');
612                 return NULL;
613         }
614         
615         Log_Debug("TCP", "srv->Connections = %p", srv->Connections);
616         Log_Debug("TCP", "srv->NewConnections = %p", srv->NewConnections);
617         Log_Debug("TCP", "srv->ConnectionsTail = %p", srv->ConnectionsTail);
618         
619         // Search
620         LOCK( &srv->lConnections );
621         for(conn = srv->Connections;
622                 conn;
623                 conn = conn->Next)
624         {
625                 LOG("conn->Node.ImplInt = %i", conn->Node.ImplInt);
626                 if(conn->Node.ImplInt == id)    break;
627         }
628         RELEASE( &srv->lConnections );
629         
630         // If not found, ret NULL
631         if(!conn) {
632                 LOG("Connection %i not found", id);
633                 LEAVE('n');
634                 return NULL;
635         }
636         
637         // Return node
638         LEAVE('p', &conn->Node);
639         return &conn->Node;
640 }
641
642 /**
643  * \brief Handle IOCtl calls
644  */
645 int TCP_Server_IOCtl(tVFS_Node *Node, int ID, void *Data)
646 {
647         tTCPListener    *srv = Node->ImplPtr;
648
649         switch(ID)
650         {
651         case 4: // Get/Set Port
652                 if(!Data)       // Get Port
653                         return srv->Port;
654
655                 if(srv->Port)   // Wait, you can't CHANGE the port
656                         return -1;
657
658                 if(!CheckMem(Data, sizeof(Uint16)))     // Sanity check
659                         return -1;
660
661                 // Permissions check
662                 if(Threads_GetUID() != 0
663                 && *(Uint16*)Data != 0
664                 && *(Uint16*)Data < 1024)
665                         return -1;
666
667                 // TODO: Check if a port is in use
668
669                 // Set Port
670                 srv->Port = *(Uint16*)Data;
671                 if(srv->Port == 0)      // Allocate a random port
672                         srv->Port = TCP_GetUnusedPort();
673                 else    // Else, mark this as used
674                         TCP_AllocatePort(srv->Port);
675                 
676                 Log_Log("TCP", "Server %p listening on port %i", srv, srv->Port);
677                 
678                 return srv->Port;
679         }
680         return 0;
681 }
682
683 void TCP_Server_Close(tVFS_Node *Node)
684 {
685         free(Node->ImplPtr);
686 }
687
688 // --- Client
689 /**
690  * \brief Create a client node
691  */
692 tVFS_Node *TCP_Client_Init(tInterface *Interface)
693 {
694         tTCPConnection  *conn = malloc( sizeof(tTCPConnection) );
695
696         conn->State = TCP_ST_CLOSED;
697         conn->Interface = Interface;
698         conn->LocalPort = -1;
699         conn->RemotePort = -1;
700         memset( &conn->RemoteIP, 0, sizeof(conn->RemoteIP) );
701
702         conn->Node.ImplPtr = conn;
703         conn->Node.NumACLs = 1;
704         conn->Node.ACLs = &gVFS_ACL_EveryoneRW;
705         conn->Node.Read = TCP_Client_Read;
706         conn->Node.Write = TCP_Client_Write;
707         conn->Node.IOCtl = TCP_Client_IOCtl;
708         conn->Node.Close = TCP_Client_Close;
709
710         conn->RecievedBuffer = RingBuffer_Create( TCP_RECIEVE_BUFFER_SIZE );
711
712         LOCK(&glTCP_OutbountCons);
713         conn->Next = gTCP_OutbountCons;
714         gTCP_OutbountCons = conn;
715         RELEASE(&glTCP_OutbountCons);
716
717         return &conn->Node;
718 }
719
720 /**
721  * \brief Wait for a packet and return it
722  * \note If \a Length is smaller than the size of the packet, the rest
723  *       of the packet's data will be discarded.
724  */
725 Uint64 TCP_Client_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
726 {
727         tTCPConnection  *conn = Node->ImplPtr;
728         char    *destbuf = Buffer;
729         size_t  len;
730         
731         ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
732         LOG("conn = %p", conn);
733         LOG("conn->State = %i", conn->State);
734         
735         // Check if connection is open
736         while( conn->State == TCP_ST_HALFOPEN || conn->State == TCP_ST_SYN_SENT )
737                 Threads_Yield();
738         if( conn->State != TCP_ST_OPEN ) {
739                 LEAVE('i', 0);
740                 return 0;
741         }
742         
743         // Poll packets
744         for(;;)
745         {
746                 // Lock list and check if there is a packet
747                 LOCK( &conn->lRecievedPackets );
748                 if( conn->RecievedBuffer->Length == 0 ) {
749                         // If not, release the lock, yield and try again
750                         RELEASE( &conn->lRecievedPackets );
751                         Threads_Yield();
752                         continue;
753                 }
754                 
755                 // Attempt to read all `Length` bytes
756                 len = RingBuffer_Read( destbuf, conn->RecievedBuffer, Length );
757                 
758                 // Release the lock (we don't need it any more)
759                 RELEASE( &conn->lRecievedPackets );
760         
761                 LEAVE('i', len);
762                 return len;
763         }
764 }
765
766 /**
767  * \brief Send a data packet on a connection
768  */
769 void TCP_INT_SendDataPacket(tTCPConnection *Connection, size_t Length, void *Data)
770 {
771         char    buf[sizeof(tTCPHeader)+Length];
772         tTCPHeader      *packet = (void*)buf;
773         
774         packet->SourcePort = htons(Connection->LocalPort);
775         packet->DestPort = htons(Connection->RemotePort);
776         packet->DataOffset = (sizeof(tTCPHeader)/4)*16;
777         packet->WindowSize = TCP_WINDOW_SIZE;
778         
779         packet->AcknowlegementNumber = htonl(Connection->NextSequenceRcv);
780         packet->SequenceNumber = htonl(Connection->NextSequenceSend);
781         packet->Flags = TCP_FLAG_PSH|TCP_FLAG_ACK;      // Hey, ACK if you can!
782         
783         memcpy(packet->Options, Data, Length);
784         
785         TCP_SendPacket( Connection, sizeof(tTCPHeader)+Length, packet );
786         
787         Connection->NextSequenceSend += Length;
788 }
789
790 /**
791  * \brief Send some bytes on a connection
792  */
793 Uint64 TCP_Client_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
794 {
795         tTCPConnection  *conn = Node->ImplPtr;
796         size_t  rem = Length;
797         
798         ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
799         
800         // Check if connection is open
801         while( conn->State == TCP_ST_HALFOPEN || conn->State == TCP_ST_SYN_SENT )
802                 Threads_Yield();
803         if( conn->State != TCP_ST_OPEN ) {
804                 LEAVE('i', 0);
805                 return 0;
806         }
807         
808         while( rem > TCP_MAX_PACKET_SIZE )
809         {
810                 TCP_INT_SendDataPacket(conn, TCP_MAX_PACKET_SIZE, Buffer);
811                 Buffer += TCP_MAX_PACKET_SIZE;
812         }
813         
814         TCP_INT_SendDataPacket(conn, rem, Buffer);
815         
816         LEAVE('i', Length);
817         return Length;
818 }
819
820 /**
821  * \brief Open a connection to another host using TCP
822  * \param Conn  Connection structure
823  */
824 void TCP_StartConnection(tTCPConnection *Conn)
825 {
826         tTCPHeader      hdr;
827
828         Conn->State = TCP_ST_SYN_SENT;
829
830         hdr.SourcePort = htons(Conn->LocalPort);
831         hdr.DestPort = htons(Conn->RemotePort);
832         Conn->NextSequenceSend = rand();
833         hdr.SequenceNumber = htonl(Conn->NextSequenceSend);
834         hdr.DataOffset = (sizeof(tTCPHeader)/4) << 4;
835         hdr.Flags = TCP_FLAG_SYN;
836         hdr.WindowSize = htons(TCP_WINDOW_SIZE);        // Max
837         hdr.Checksum = 0;       // TODO
838         hdr.UrgentPointer = 0;
839         
840         TCP_SendPacket( Conn, sizeof(tTCPHeader), &hdr );
841         
842         Conn->NextSequenceSend ++;
843         Conn->State = TCP_ST_SYN_SENT;
844         return ;
845 }
846
847 /**
848  * \brief Control a client socket
849  */
850 int TCP_Client_IOCtl(tVFS_Node *Node, int ID, void *Data)
851 {
852         tTCPConnection  *conn = Node->ImplPtr;
853
854         switch(ID)
855         {
856         case 4: // Get/Set local port
857                 if(!Data)
858                         return conn->LocalPort;
859                 if(conn->State != TCP_ST_CLOSED)
860                         return -1;
861                 if(!CheckMem(Data, sizeof(Uint16)))
862                         return -1;
863
864                 if(Threads_GetUID() != 0 && *(Uint16*)Data < 1024)
865                         return -1;
866
867                 conn->LocalPort = *(Uint16*)Data;
868                 return 0;
869
870         case 5: // Get/Set remote port
871                 if(!Data)       return conn->RemotePort;
872                 if(conn->State != TCP_ST_CLOSED)        return -1;
873                 if(!CheckMem(Data, sizeof(Uint16)))     return -1;
874                 conn->RemotePort = *(Uint16*)Data;
875                 return 0;
876
877         case 6: // Set Remote IP
878                 if( conn->State != TCP_ST_CLOSED )
879                         return -1;
880                 if( conn->Interface->Type == 4 )
881                 {
882                         if(!CheckMem(Data, sizeof(tIPv4)))      return -1;
883                         conn->RemoteIP.v4 = *(tIPv4*)Data;
884                 }
885                 else if( conn->Interface->Type == 6 )
886                 {
887                         if(!CheckMem(Data, sizeof(tIPv6)))      return -1;
888                         conn->RemoteIP.v6 = *(tIPv6*)Data;
889                 }
890                 return 0;
891
892         case 7: // Connect
893                 if(conn->LocalPort == 0xFFFF)
894                         conn->LocalPort = TCP_GetUnusedPort();
895                 if(conn->RemotePort == -1)
896                         return 0;
897
898                 TCP_StartConnection(conn);
899                 return 1;
900         }
901
902         return 0;
903 }
904
905 void TCP_Client_Close(tVFS_Node *Node)
906 {
907         tTCPConnection  *conn = Node->ImplPtr;
908         tTCPHeader      packet;
909         
910         packet.SourcePort = htons(conn->LocalPort);
911         packet.DestPort = htons(conn->RemotePort);
912         packet.DataOffset = (sizeof(tTCPHeader)/4)*16;
913         packet.WindowSize = TCP_WINDOW_SIZE;
914         
915         packet.AcknowlegementNumber = 0;
916         packet.SequenceNumber = htonl(conn->NextSequenceSend);
917         packet.Flags = TCP_FLAG_FIN;
918         
919         conn->State = TCP_ST_FIN_SENT;
920         
921         TCP_SendPacket( conn, sizeof(tTCPHeader), &packet );
922         
923         while( conn->State == TCP_ST_FIN_SENT ) Threads_Yield();
924         
925         free(conn);
926 }

UCC git Repository :: git.ucc.asn.au