// --- Server
tVFS_Node *TCP_Server_Init(tInterface *Interface);
int TCP_Server_ReadDir(tVFS_Node *Node, int Pos, char Name[FILENAME_MAX]);
-tVFS_Node *TCP_Server_FindDir(tVFS_Node *Node, const char *Name);
+tVFS_Node *TCP_Server_FindDir(tVFS_Node *Node, const char *Name, Uint Flags);
int TCP_Server_IOCtl(tVFS_Node *Node, int ID, void *Data);
void TCP_Server_Close(tVFS_Node *Node);
// --- Client
tVFS_Node *TCP_Client_Init(tInterface *Interface);
-size_t TCP_Client_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer);
-size_t TCP_Client_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer);
+size_t TCP_Client_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags);
+size_t TCP_Client_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags);
int TCP_Client_IOCtl(tVFS_Node *Node, int ID, void *Data);
void TCP_Client_Close(tVFS_Node *Node);
// --- Helpers
srv->NewConnections = conn;
VFS_MarkAvaliable( &srv->Node, 1 );
SHORTREL(&srv->lConnections);
+ Semaphore_Signal(&srv->WaitingConnections, 1);
// Send the SYN ACK
hdr->Flags |= TCP_FLAG_ACK;
// Get length of data
dataLen = Length - (Header->DataOffset>>4)*4;
LOG("dataLen = %i", dataLen);
-// Log_Debug("TCP", "State %i, dataLen = %x", Connection->State, dataLen);
+ Log_Debug("TCP", "State %i, dataLen = %x", Connection->State, dataLen);
//
// State Machine
if( Header->Flags & TCP_FLAG_SYN )
{
Connection->NextSequenceRcv ++;
- 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;
- TCP_SendPacket( Connection, Header, 0, NULL );
if( Header->Flags & TCP_FLAG_ACK )
{
Log_Log("TCP", "ACKing SYN-ACK");
Connection->State = TCP_ST_OPEN;
+ VFS_MarkFull(&Connection->Node, 0);
}
else
{
Log_Log("TCP", "ACKing SYN");
Connection->State = TCP_ST_SYN_RCVD;
}
+ 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;
+ TCP_SendPacket( Connection, Header, 0, NULL );
}
break;
if( Header->Flags & TCP_FLAG_ACK )
{
// TODO: Handle max half-open limit
- Connection->State = TCP_ST_OPEN;
Log_Log("TCP", "Connection fully opened");
+ Connection->State = TCP_ST_OPEN;
+ VFS_MarkFull(&Connection->Node, 0);
}
break;
}
Connection->NextSequenceRcv ++; // TODO: Is this right? (empty packet counts as one byte)
Log_Log("TCP", "Empty Packet, inc and ACK the current sequence number");
+ TCP_INT_SendACK(Connection);
+ #if 0
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, Header, 0, NULL );
+ #endif
return ;
}
sequence_num = ntohl(Header->SequenceNumber);
- LOG("TCP", "0x%08x <= 0x%08x < 0x%08x",
+ LOG("0x%08x <= 0x%08x < 0x%08x",
Connection->NextSequenceRcv,
ntohl(Header->SequenceNumber),
Connection->NextSequenceRcv + TCP_WINDOW_SIZE
ENTER("pNode iPos", Node, Pos);
Log_Log("TCP", "Thread %i waiting for a connection", Threads_GetTID());
- for(;;)
- {
- SHORTLOCK( &srv->lConnections );
- if( srv->NewConnections != NULL ) break;
- SHORTREL( &srv->lConnections );
- Threads_Yield(); // TODO: Sleep until poked
- }
+ Semaphore_Wait( &srv->WaitingConnections, 1 );
-
+ SHORTLOCK(&srv->lConnections);
// Increment the new list (the current connection is still on the
// normal list)
conn = srv->NewConnections;
* \param Node Server node
* \param Name Hexadecimal ID of the node
*/
-tVFS_Node *TCP_Server_FindDir(tVFS_Node *Node, const char *Name)
+tVFS_Node *TCP_Server_FindDir(tVFS_Node *Node, const char *Name, Uint Flags)
{
tTCPConnection *conn;
tTCPListener *srv = Node->ImplPtr;
conn->Node.NumACLs = 1;
conn->Node.ACLs = &gVFS_ACL_EveryoneRW;
conn->Node.Type = &gTCP_ClientNodeType;
+ conn->Node.BufferFull = 1; // Cleared when connection opens
conn->RecievedBuffer = RingBuffer_Create( TCP_RECIEVE_BUFFER_SIZE );
#if 0
* \note If \a Length is smaller than the size of the packet, the rest
* of the packet's data will be discarded.
*/
-size_t TCP_Client_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
+size_t TCP_Client_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags)
{
tTCPConnection *conn = Node->ImplPtr;
size_t len;
ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
LOG("conn = %p {State:%i}", conn, conn->State);
- // Check if connection is estabilishing
- // - TODO: Sleep instead (maybe using VFS_SelectNode to wait for the
- // data to be availiable
- while( conn->State == TCP_ST_SYN_RCVD || conn->State == TCP_ST_SYN_SENT )
- Threads_Yield();
-
- // If the conneciton is not open, then clean out the recieved buffer
- if( conn->State != TCP_ST_OPEN )
+ // If the connection has been closed (state > ST_OPEN) then clear
+ // any stale data in the buffer (until it is empty (until it is empty))
+ if( conn->State > TCP_ST_OPEN )
{
Mutex_Acquire( &conn->lRecievedPackets );
len = RingBuffer_Read( Buffer, conn->RecievedBuffer, Length );
if( len == 0 ) {
VFS_MarkAvaliable(Node, 0);
+ errno = 0;
LEAVE('i', -1);
return -1;
}
}
// Wait
- VFS_SelectNode(Node, VFS_SELECT_READ|VFS_SELECT_ERROR, NULL, "TCP_Client_Read");
+ {
+ tTime *timeout = NULL;
+ tTime timeout_zero = 0;
+ if( Flags & VFS_IOFLAG_NOBLOCK )
+ timeout = &timeout_zero;
+ if( !VFS_SelectNode(Node, VFS_SELECT_READ|VFS_SELECT_ERROR, timeout, "TCP_Client_Read") ) {
+ errno = EWOULDBLOCK;
+ LEAVE('i', -1);
+ return -1;
+ }
+ }
// Lock list and read as much as possible (up to `Length`)
Mutex_Acquire( &conn->lRecievedPackets );
/**
* \brief Send some bytes on a connection
*/
-size_t TCP_Client_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer)
+size_t TCP_Client_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags)
{
tTCPConnection *conn = Node->ImplPtr;
size_t rem = Length;
// Buffer, Length);
// #endif
- // Check if connection is open
- while( conn->State == TCP_ST_SYN_RCVD || conn->State == TCP_ST_SYN_SENT )
- Threads_Yield();
-
- if( conn->State != TCP_ST_OPEN ) {
+ // Don't allow a write to a closed connection
+ if( conn->State > TCP_ST_OPEN ) {
VFS_MarkError(Node, 1);
+ errno = 0;
LEAVE('i', -1);
return -1;
}
+ // Wait
+ {
+ tTime *timeout = NULL;
+ tTime timeout_zero = 0;
+ if( Flags & VFS_IOFLAG_NOBLOCK )
+ timeout = &timeout_zero;
+ if( !VFS_SelectNode(Node, VFS_SELECT_WRITE|VFS_SELECT_ERROR, timeout, "TCP_Client_Write") ) {
+ errno = EWOULDBLOCK;
+ LEAVE('i', -1);
+ return -1;
+ }
+ }
+
do
{
int len = (rem < TCP_MAX_PACKET_SIZE) ? rem : TCP_MAX_PACKET_SIZE;
LEAVE_RET('i', 0);
{
- tTime timeout_end = now() + conn->Interface->TimeoutDelay;
+ tTime timeout = conn->Interface->TimeoutDelay;
TCP_StartConnection(conn);
- // TODO: Wait for connection to open
- while( conn->State == TCP_ST_SYN_SENT && timeout_end > now() ) {
- Threads_Yield();
- }
+ VFS_SelectNode(&conn->Node, VFS_SELECT_WRITE, &timeout, "TCP Connection");
if( conn->State == TCP_ST_SYN_SENT )
LEAVE_RET('i', 0);
}
while( conn->State == TCP_ST_FIN_WAIT1 ) Threads_Yield();
break;
default:
- Log_Warning("TCP", "Unhandled connection state in TCP_Client_Close");
+ Log_Warning("TCP", "Unhandled connection state %i in TCP_Client_Close",
+ conn->State);
break;
}