in FreeRTOS_TCP_IP.c [2089:2288]
static int32_t prvTCPPrepareSend( FreeRTOS_Socket_t * pxSocket,
NetworkBufferDescriptor_t ** ppxNetworkBuffer,
UBaseType_t uxOptionsLength )
{
int32_t lDataLen;
uint8_t * pucEthernetBuffer, * pucSendData;
ProtocolHeaders_t * pxProtocolHeaders;
size_t uxOffset;
uint32_t ulDataGot, ulDistance;
TCPWindow_t * pxTCPWindow;
NetworkBufferDescriptor_t * pxNewBuffer;
int32_t lStreamPos;
UBaseType_t uxIntermediateResult = 0;
if( ( *ppxNetworkBuffer ) != NULL )
{
/* A network buffer descriptor was already supplied */
pucEthernetBuffer = ( *ppxNetworkBuffer )->pucEthernetBuffer;
}
else
{
/* For now let it point to the last packet header */
pucEthernetBuffer = pxSocket->u.xTCP.xPacket.u.ucLastPacket;
}
/* Map the ethernet buffer onto the ProtocolHeader_t struct for easy access to the fields. */
pxProtocolHeaders = ipCAST_PTR_TO_TYPE_PTR( ProtocolHeaders_t, &( pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + uxIPHeaderSizeSocket( pxSocket ) ] ) );
pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );
lDataLen = 0;
lStreamPos = 0;
pxProtocolHeaders->xTCPHeader.ucTCPFlags |= tcpTCP_FLAG_ACK;
if( pxSocket->u.xTCP.txStream != NULL )
{
/* ulTCPWindowTxGet will return the amount of data which may be sent
* along with the position in the txStream.
* Why check for MSS > 1 ?
* Because some TCP-stacks (like uIP) use it for flow-control. */
if( pxSocket->u.xTCP.usMSS > 1U )
{
lDataLen = ( int32_t ) ulTCPWindowTxGet( pxTCPWindow, pxSocket->u.xTCP.ulWindowSize, &lStreamPos );
}
if( lDataLen > 0 )
{
/* Check if the current network buffer is big enough, if not,
* resize it. */
pxNewBuffer = prvTCPBufferResize( pxSocket, *ppxNetworkBuffer, lDataLen, uxOptionsLength );
if( pxNewBuffer != NULL )
{
*ppxNetworkBuffer = pxNewBuffer;
pucEthernetBuffer = pxNewBuffer->pucEthernetBuffer;
/* Map the byte stream onto ProtocolHeaders_t struct for easy
* access to the fields. */
pxProtocolHeaders = ipCAST_PTR_TO_TYPE_PTR( ProtocolHeaders_t, &( pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + uxIPHeaderSizeSocket( pxSocket ) ] ) );
pucSendData = &( pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + uxIPHeaderSizeSocket( pxSocket ) + ipSIZE_OF_TCP_HEADER + uxOptionsLength ] );
/* Translate the position in txStream to an offset from the tail
* marker. */
uxOffset = uxStreamBufferDistance( pxSocket->u.xTCP.txStream, pxSocket->u.xTCP.txStream->uxTail, ( size_t ) lStreamPos );
/* Here data is copied from the txStream in 'peek' mode. Only
* when the packets are acked, the tail marker will be updated. */
ulDataGot = ( uint32_t ) uxStreamBufferGet( pxSocket->u.xTCP.txStream, uxOffset, pucSendData, ( size_t ) lDataLen, pdTRUE );
#if ( ipconfigHAS_DEBUG_PRINTF != 0 )
{
if( ulDataGot != ( uint32_t ) lDataLen )
{
FreeRTOS_debug_printf( ( "uxStreamBufferGet: pos %d offs %u only %u != %d\n",
( int ) lStreamPos, ( unsigned ) uxOffset, ( unsigned ) ulDataGot, ( int ) lDataLen ) );
}
}
#endif
/* If the owner of the socket requests a closure, add the FIN
* flag to the last packet. */
if( pxSocket->u.xTCP.bits.bCloseRequested != pdFALSE_UNSIGNED )
{
ulDistance = ( uint32_t ) uxStreamBufferDistance( pxSocket->u.xTCP.txStream, ( size_t ) lStreamPos, pxSocket->u.xTCP.txStream->uxHead );
if( ulDistance == ulDataGot )
{
#if ( ipconfigHAS_DEBUG_PRINTF == 1 )
{
/* the order of volatile accesses is undefined
* so such workaround */
size_t uxHead = pxSocket->u.xTCP.txStream->uxHead;
size_t uxMid = pxSocket->u.xTCP.txStream->uxMid;
size_t uxTail = pxSocket->u.xTCP.txStream->uxTail;
FreeRTOS_debug_printf( ( "CheckClose %u <= %u (%u <= %u <= %u)\n",
( unsigned ) ulDataGot, ( unsigned ) ulDistance,
( unsigned ) uxTail, ( unsigned ) uxMid, ( unsigned ) uxHead ) );
}
#endif /* if ( ipconfigHAS_DEBUG_PRINTF == 1 ) */
/* Although the socket sends a FIN, it will stay in
* ESTABLISHED until all current data has been received or
* delivered. */
pxProtocolHeaders->xTCPHeader.ucTCPFlags |= tcpTCP_FLAG_FIN;
pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->ulOurSequenceNumber + ( uint32_t ) lDataLen;
pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;
}
}
}
else
{
lDataLen = -1;
}
}
}
if( ( lDataLen >= 0 ) && ( pxSocket->u.xTCP.ucTCPState == ( uint8_t ) eESTABLISHED ) )
{
/* See if the socket owner wants to shutdown this connection. */
if( ( pxSocket->u.xTCP.bits.bUserShutdown != pdFALSE_UNSIGNED ) &&
( xTCPWindowTxDone( pxTCPWindow ) != pdFALSE ) )
{
pxSocket->u.xTCP.bits.bUserShutdown = pdFALSE_UNSIGNED;
pxProtocolHeaders->xTCPHeader.ucTCPFlags |= tcpTCP_FLAG_FIN;
pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED;
pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED;
pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber;
vTCPStateChange( pxSocket, eFIN_WAIT_1 );
}
#if ( ipconfigTCP_KEEP_ALIVE != 0 )
{
if( pxSocket->u.xTCP.ucKeepRepCount > 3U ) /*_RB_ Magic number. */
{
FreeRTOS_debug_printf( ( "keep-alive: giving up %xip:%u\n",
( unsigned ) pxSocket->u.xTCP.ulRemoteIP, /* IP address of remote machine. */
pxSocket->u.xTCP.usRemotePort ) ); /* Port on remote machine. */
vTCPStateChange( pxSocket, eCLOSE_WAIT );
lDataLen = -1;
}
if( ( lDataLen == 0 ) && ( pxSocket->u.xTCP.bits.bWinChange == pdFALSE_UNSIGNED ) )
{
/* If there is no data to be sent, and no window-update message,
* we might want to send a keep-alive message. */
TickType_t xAge = xTaskGetTickCount() - pxSocket->u.xTCP.xLastAliveTime;
TickType_t xMax;
xMax = ( ( TickType_t ) ipconfigTCP_KEEP_ALIVE_INTERVAL * ( TickType_t ) configTICK_RATE_HZ );
if( pxSocket->u.xTCP.ucKeepRepCount != 0U )
{
xMax = 3U * configTICK_RATE_HZ;
}
if( xAge > xMax )
{
pxSocket->u.xTCP.xLastAliveTime = xTaskGetTickCount();
if( xTCPWindowLoggingLevel != 0 )
{
FreeRTOS_debug_printf( ( "keep-alive: %xip:%u count %u\n",
( unsigned ) pxSocket->u.xTCP.ulRemoteIP,
pxSocket->u.xTCP.usRemotePort,
pxSocket->u.xTCP.ucKeepRepCount ) );
}
pxSocket->u.xTCP.bits.bSendKeepAlive = pdTRUE_UNSIGNED;
pxSocket->u.xTCP.usTimeout = ( ( uint16_t ) pdMS_TO_TICKS( 2500U ) );
pxSocket->u.xTCP.ucKeepRepCount++;
}
}
}
#endif /* ipconfigTCP_KEEP_ALIVE */
}
if( lDataLen >= 0 )
{
/* Anything to send, a change of the advertised window size, or maybe send a
* keep-alive message? */
if( ( lDataLen > 0 ) ||
( pxSocket->u.xTCP.bits.bWinChange != pdFALSE_UNSIGNED ) ||
( pxSocket->u.xTCP.bits.bSendKeepAlive != pdFALSE_UNSIGNED ) )
{
pxProtocolHeaders->xTCPHeader.ucTCPFlags &= ( ( uint8_t ) ~tcpTCP_FLAG_PSH );
pxProtocolHeaders->xTCPHeader.ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 ); /*_RB_ "2" needs comment. */
pxProtocolHeaders->xTCPHeader.ucTCPFlags |= ( uint8_t ) tcpTCP_FLAG_ACK;
if( lDataLen != 0L )
{
pxProtocolHeaders->xTCPHeader.ucTCPFlags |= ( uint8_t ) tcpTCP_FLAG_PSH;
}
uxIntermediateResult = uxIPHeaderSizeSocket( pxSocket ) + ipSIZE_OF_TCP_HEADER + uxOptionsLength;
lDataLen += ( int32_t ) uxIntermediateResult;
}
}
return lDataLen;
}