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

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