static int32_t prvTCPPrepareSend()

in amazon-freertos/lib/FreeRTOS-Plus-TCP/source/FreeRTOS_TCP_IP.c [1674:1853]


static int32_t prvTCPPrepareSend( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer, UBaseType_t uxOptionsLength )
{
int32_t lDataLen;
uint8_t *pucEthernetBuffer, *pucSendData;
TCPPacket_t *pxTCPPacket;
size_t uxOffset;
uint32_t ulDataGot, ulDistance;
TCPWindow_t *pxTCPWindow;
NetworkBufferDescriptor_t *pxNewBuffer;
int32_t lStreamPos;

	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;
	}

	pxTCPPacket = ( TCPPacket_t * ) ( pucEthernetBuffer );
	pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow;
	lDataLen = 0;
	lStreamPos = 0;
	pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_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.usCurMSS > 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;
				pxTCPPacket = ( TCPPacket_t * ) ( pucEthernetBuffer );

				pucSendData = pucEthernetBuffer + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + 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 %lu offs %lu only %lu != %lu\n",
							lStreamPos, uxOffset, ulDataGot, 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 ) && ( pxSocket->u.xTCP.bits.bFinSent == 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 %lu <= %lu (%lu <= %lu <= %lu)\n", ulDataGot, ulDistance,
								uxTail, uxMid, uxHead ) );
						}
						#endif
						/* Although the socket sends a FIN, it will stay in
						ESTABLISHED until all current data has been received or
						delivered. */
						pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_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 == 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;
			pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_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 )
			{
				FreeRTOS_debug_printf( ( "keep-alive: giving up %lxip:%u\n",
					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 * configTICK_RATE_HZ );
				if( pxSocket->u.xTCP.ucKeepRepCount )
				{
					xMax = ( 3u * configTICK_RATE_HZ );
				}
				if( xAge > xMax )
				{
					pxSocket->u.xTCP.xLastAliveTime = xTaskGetTickCount( );
					if( xTCPWindowLoggingLevel )
						FreeRTOS_debug_printf( ( "keep-alive: %lxip:%u count %u\n",
							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( 2500 ) );
					pxSocket->u.xTCP.ucKeepRepCount++;
				}
			}
		}
		#endif /* ipconfigTCP_KEEP_ALIVE */
	}

	/* 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 ) )
	{
		pxTCPPacket->xTCPHeader.ucTCPFlags &= ( ( uint8_t ) ~ipTCP_FLAG_PSH );
		pxTCPPacket->xTCPHeader.ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );

		pxTCPPacket->xTCPHeader.ucTCPFlags |= ( uint8_t ) ipTCP_FLAG_ACK;

		if( lDataLen != 0l )
		{
			pxTCPPacket->xTCPHeader.ucTCPFlags |= ( uint8_t ) ipTCP_FLAG_PSH;
		}

		lDataLen += ( int32_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
	}

	return lDataLen;
}