Exemplo n.º 1
0
void tcpStateCloseWait(Socket *socket, TcpHeader *segment, size_t length)
{
   uint_t flags = 0;

   //Debug message
   TRACE_DEBUG("TCP FSM: CLOSE-WAIT state\r\n");

   //First check sequence number
   if(tcpCheckSequenceNumber(socket, segment, length))
      return;

   //Check the RST bit
   if(segment->flags & TCP_FLAG_RST)
   {
      //Switch to the CLOSED state
      tcpChangeState(socket, TCP_STATE_CLOSED);

      //Number of times TCP connections have made a direct transition to the
      //CLOSED state from either the ESTABLISHED state or the CLOSE-WAIT state
      MIB2_INC_COUNTER32(mib2Base.tcpGroup.tcpEstabResets, 1);

      //Return immediately
      return;
   }

   //Check the SYN bit
   if(tcpCheckSyn(socket, segment, length))
      return;
   //Check the ACK field
   if(tcpCheckAck(socket, segment, length))
      return;

#if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
   //Duplicate AK received?
   if(socket->dupAckCount > 0)
      flags = SOCKET_FLAG_NO_DELAY;
#endif

   //The Nagle algorithm should be implemented to coalesce
   //short segments (refer to RFC 1122 4.2.3.4)
   tcpNagleAlgo(socket, flags);
}
Exemplo n.º 2
0
void tcpStateEstablished(Socket *socket, TcpHeader *segment,
   const NetBuffer *buffer, size_t offset, size_t length)
{
   uint_t flags = 0;

   //Debug message
   TRACE_DEBUG("TCP FSM: ESTABLISHED state\r\n");

   //First check sequence number
   if(tcpCheckSequenceNumber(socket, segment, length))
      return;

   //Check the RST bit
   if(segment->flags & TCP_FLAG_RST)
   {
      //Switch to the CLOSED state
      tcpChangeState(socket, TCP_STATE_CLOSED);

      //Number of times TCP connections have made a direct transition to the
      //CLOSED state from either the ESTABLISHED state or the CLOSE-WAIT state
      MIB2_INC_COUNTER32(mib2Base.tcpGroup.tcpEstabResets, 1);

      //Return immediately
      return;
   }

   //Check the SYN bit
   if(tcpCheckSyn(socket, segment, length))
      return;
   //Check the ACK field
   if(tcpCheckAck(socket, segment, length))
      return;
   //Process the segment text
   if(length > 0)
      tcpProcessSegmentData(socket, segment, buffer, offset, length);

   //Check the FIN bit
   if(segment->flags & TCP_FLAG_FIN)
   {
      //The FIN can only be acknowledged if all the segment data
      //has been successfully transferred to the receive buffer
      if(socket->rcvNxt == (segment->seqNum + length))
      {
         //Advance RCV.NXT over the FIN
         socket->rcvNxt++;
         //Send an acknowledgement for the FIN
         tcpSendSegment(socket, TCP_FLAG_ACK, socket->sndNxt, socket->rcvNxt, 0, FALSE);
         //Switch to the CLOSE-WAIT state
         tcpChangeState(socket, TCP_STATE_CLOSE_WAIT);
      }
   }

#if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
   //Duplicate AK received?
   if(socket->dupAckCount > 0)
      flags = SOCKET_FLAG_NO_DELAY;
#endif

   //The Nagle algorithm should be implemented to coalesce
   //short segments (refer to RFC 1122 4.2.3.4)
   tcpNagleAlgo(socket, flags);
}
Exemplo n.º 3
0
error_t tcpSend(Socket *socket, const uint8_t *data,
   size_t length, size_t *written, uint_t flags)
{
   uint_t n;
   uint_t totalLength;
   uint_t event;

   //Check whether the socket is in the listening state
   if(socket->state == TCP_STATE_LISTEN)
      return ERROR_NOT_CONNECTED;

   //Actual number of bytes written
   totalLength = 0;

   //Send as much data as possible
   do
   {
      //Wait until there is more room in the send buffer
      event = tcpWaitForEvents(socket, SOCKET_EVENT_TX_READY, socket->timeout);

      //A timeout exception occurred?
      if(event != SOCKET_EVENT_TX_READY)
         return ERROR_TIMEOUT;

      //Check current TCP state
      switch(socket->state)
      {
      //ESTABLISHED or CLOSE-WAIT state?
      case TCP_STATE_ESTABLISHED:
      case TCP_STATE_CLOSE_WAIT:
         //The send buffer is now available for writing
         break;

      //LAST-ACK, FIN-WAIT-1, FIN-WAIT-2, CLOSING or TIME-WAIT state?
      case TCP_STATE_LAST_ACK:
      case TCP_STATE_FIN_WAIT_1:
      case TCP_STATE_FIN_WAIT_2:
      case TCP_STATE_CLOSING:
      case TCP_STATE_TIME_WAIT:
         //The connection is being closed
         return ERROR_CONNECTION_CLOSING;

      //CLOSED state?
      default:
         //The connection was reset by remote side?
         return (socket->resetFlag) ? ERROR_CONNECTION_RESET : ERROR_NOT_CONNECTED;
      }

      //Determine the actual number of bytes in the send buffer
      n = socket->sndUser + socket->sndNxt - socket->sndUna;
      //Exit immediately if the transmission buffer is full (sanity check)
      if(n >= socket->txBufferSize)
         return ERROR_FAILURE;

      //Number of bytes available for writing
      n = socket->txBufferSize - n;
      //Calculate the number of bytes to copy at a time
      n = MIN(n, length - totalLength);

      //Any data to copy?
      if(n > 0)
      {
         //Copy user data to send buffer
         tcpWriteTxBuffer(socket, socket->sndNxt + socket->sndUser, data, n);

         //Update the number of data buffered but not yet sent
         socket->sndUser += n;
         //Advance data pointer
         data += n;
         //Update byte counter
         totalLength += n;

         //Total number of data that have been written
         if(written != NULL)
            *written = totalLength;

         //Update TX events
         tcpUpdateEvents(socket);

         //To avoid a deadlock, it is necessary to have a timeout to force
         //transmission of data, overriding the SWS avoidance algorithm. In
         //practice, this timeout should seldom occur (see RFC 1122 4.2.3.4)
         if(socket->sndUser == n)
            tcpTimerStart(&socket->overrideTimer, TCP_OVERRIDE_TIMEOUT);
      }

      //The Nagle algorithm should be implemented to coalesce
      //short segments (refer to RFC 1122 4.2.3.4)
      tcpNagleAlgo(socket, flags);

      //Send as much data as possible
   } while(totalLength < length);

   //The SOCKET_FLAG_WAIT_ACK flag causes the function to
   //wait for acknowledgement from the remote side
   if(flags & SOCKET_FLAG_WAIT_ACK)
   {
      //Wait for the data to be acknowledged
      event = tcpWaitForEvents(socket, SOCKET_EVENT_TX_ACKED, socket->timeout);

      //A timeout exception occurred?
      if(event != SOCKET_EVENT_TX_ACKED)
         return ERROR_TIMEOUT;

      //The connection was closed before an acknowledgement was received?
      if(socket->state != TCP_STATE_ESTABLISHED && socket->state != TCP_STATE_CLOSE_WAIT)
         return ERROR_NOT_CONNECTED;
   }

   //Successful write operation
   return NO_ERROR;
}