1
0
mirror of https://github.com/FreeRTOS/FreeRTOS-Plus-TCP synced 2025-10-20 22:10:04 +08:00
Files
FreeRTOS-Plus-TCP/source/FreeRTOS_IP_Timers.c
Hein Tibosch 188a9d02f4 IPv4/single: connect() should return immediately after a protocol error and other things (#559)
* IPv4/single: Let connect() return as soon as socket gets closed

* Let both connect() and accept() return after a 'eSOCKET_CLOSED' event

* Included hang protection of orphaned socket from PR #545

* Lexicon.txt change

* Remove a variable that was not used

* Update source/FreeRTOS_Sockets.c

Co-authored-by: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com>

* Update source/FreeRTOS_TCP_IP.c

Co-authored-by: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com>

* moved declaration to beginning of block

* Update source/FreeRTOS_TCP_IP.c

Co-authored-by: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com>

* Uncrustify: triggered by comment.

* Fix unit test expectations

* Avoid a recursive call to vTCPStateChange()

* Uncrustify: triggered by comment.

* Fix CBMC proof assumptions

* Get unit-test coverage up

* Fix timers unit-tests

* Socket unit-test for closed socket

* Fix a unit-test expectations

* Fix spell check

* Uncrustify: triggered by comment.

* Using debug_printf in stead of printf for logging.

* Use debug printf instead of printf in 2 locations

Co-authored-by: Hein Tibosch <hein@htibosch.net>
Co-authored-by: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Co-authored-by: GitHub Action <action@github.com>
2022-10-11 14:20:13 -07:00

484 lines
14 KiB
C

/*
* FreeRTOS+TCP <DEVELOPMENT BRANCH>
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_ICMP.c
* @brief Implements the Internet Control Message Protocol for the FreeRTOS+TCP network stack.
*/
/* Standard includes. */
#include <stdint.h>
#include <stdio.h>
#include <string.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_IP_Timers.h"
#include "FreeRTOS_IP_Utils.h"
#include "FreeRTOS_Sockets.h"
#include "FreeRTOS_IP_Private.h"
#include "FreeRTOS_ARP.h"
#include "FreeRTOS_UDP_IP.h"
#include "FreeRTOS_DHCP.h"
#include "NetworkInterface.h"
#include "NetworkBufferManagement.h"
#include "FreeRTOS_DNS.h"
/*
* Utility functions for the light weight IP timers.
*/
static void prvIPTimerStart( IPTimer_t * pxTimer,
TickType_t xTime );
static BaseType_t prvIPTimerCheck( IPTimer_t * pxTimer );
static void prvIPTimerReload( IPTimer_t * pxTimer,
TickType_t xTime );
/*
* A timer for each of the following processes, all of which need attention on a
* regular basis
*/
/** @brief Timer to limit the maximum time a packet should be stored while
* awaiting an ARP resolution. */
static IPTimer_t xARPResolutionTimer;
/** @brief ARP timer, to check its table entries. */
static IPTimer_t xARPTimer;
#if ( ipconfigUSE_DHCP != 0 )
/** @brief DHCP timer, to send requests and to renew a reservation. */
static IPTimer_t xDHCPTimer;
#endif
#if ( ipconfigUSE_TCP != 0 )
/** @brief TCP timer, to check for timeouts, resends. */
static IPTimer_t xTCPTimer;
#endif
#if ( ipconfigDNS_USE_CALLBACKS != 0 )
/** @brief DNS timer, to check for timeouts when looking-up a domain. */
static IPTimer_t xDNSTimer;
#endif
/**
* @brief Calculate the maximum sleep time remaining. It will go through all
* timers to see which timer will expire first. That will be the amount
* of time to block in the next call to xQueueReceive().
*
* @return The maximum sleep time or ipconfigMAX_IP_TASK_SLEEP_TIME,
* whichever is smaller.
*/
TickType_t xCalculateSleepTime( void )
{
TickType_t uxMaximumSleepTime;
/* Start with the maximum sleep time, then check this against the remaining
* time in any other timers that are active. */
uxMaximumSleepTime = ipconfigMAX_IP_TASK_SLEEP_TIME;
if( xARPTimer.bActive != pdFALSE_UNSIGNED )
{
if( xARPTimer.ulRemainingTime < uxMaximumSleepTime )
{
uxMaximumSleepTime = xARPTimer.ulRemainingTime;
}
}
#if ( ipconfigUSE_DHCP == 1 )
{
if( xDHCPTimer.bActive != pdFALSE_UNSIGNED )
{
if( xDHCPTimer.ulRemainingTime < uxMaximumSleepTime )
{
uxMaximumSleepTime = xDHCPTimer.ulRemainingTime;
}
}
}
#endif /* ipconfigUSE_DHCP */
#if ( ipconfigUSE_TCP == 1 )
{
if( xTCPTimer.bActive != pdFALSE_UNSIGNED )
{
if( xTCPTimer.ulRemainingTime < uxMaximumSleepTime )
{
uxMaximumSleepTime = xTCPTimer.ulRemainingTime;
}
}
}
#endif
#if ( ipconfigDNS_USE_CALLBACKS != 0 )
{
if( xDNSTimer.bActive != pdFALSE_UNSIGNED )
{
if( xDNSTimer.ulRemainingTime < uxMaximumSleepTime )
{
uxMaximumSleepTime = xDNSTimer.ulRemainingTime;
}
}
}
#endif
return uxMaximumSleepTime;
}
/*-----------------------------------------------------------*/
/**
* @brief Check the network timers (ARP/DHCP/DNS/TCP) and if they are
* expired, send an event to the IP-Task.
*/
void vCheckNetworkTimers( void )
{
/* Is it time for ARP processing? */
if( prvIPTimerCheck( &xARPTimer ) != pdFALSE )
{
( void ) xSendEventToIPTask( eARPTimerEvent );
}
/* Is the ARP resolution timer expired? */
if( prvIPTimerCheck( &xARPResolutionTimer ) != pdFALSE )
{
if( pxARPWaitingNetworkBuffer != NULL )
{
/* Disable the ARP resolution timer. */
vIPSetARPResolutionTimerEnableState( pdFALSE );
/* We have waited long enough for the ARP response. Now, free the network
* buffer. */
vReleaseNetworkBufferAndDescriptor( pxARPWaitingNetworkBuffer );
/* Clear the pointer. */
pxARPWaitingNetworkBuffer = NULL;
iptraceDELAYED_ARP_TIMER_EXPIRED();
}
}
#if ( ipconfigUSE_DHCP == 1 )
{
/* Is it time for DHCP processing? */
if( prvIPTimerCheck( &xDHCPTimer ) != pdFALSE )
{
( void ) xSendDHCPEvent();
}
}
#endif /* ipconfigUSE_DHCP */
#if ( ipconfigDNS_USE_CALLBACKS != 0 )
{
/* Is it time for DNS processing? */
if( prvIPTimerCheck( &xDNSTimer ) != pdFALSE )
{
vDNSCheckCallBack( NULL );
}
}
#endif /* ipconfigDNS_USE_CALLBACKS */
#if ( ipconfigUSE_TCP == 1 )
{
BaseType_t xWillSleep;
TickType_t xNextTime;
BaseType_t xCheckTCPSockets;
/* If the IP task has messages waiting to be processed then
* it will not sleep in any case. */
if( uxQueueMessagesWaiting( xNetworkEventQueue ) == 0U )
{
xWillSleep = pdTRUE;
}
else
{
xWillSleep = pdFALSE;
}
/* Sockets need to be checked if the TCP timer has expired. */
xCheckTCPSockets = prvIPTimerCheck( &xTCPTimer );
/* Sockets will also be checked if there are TCP messages but the
* message queue is empty (indicated by xWillSleep being true). */
if( ( xProcessedTCPMessage != pdFALSE ) && ( xWillSleep != pdFALSE ) )
{
xCheckTCPSockets = pdTRUE;
}
if( xCheckTCPSockets != pdFALSE )
{
/* Attend to the sockets, returning the period after which the
* check must be repeated. */
xNextTime = xTCPTimerCheck( xWillSleep );
prvIPTimerStart( &xTCPTimer, xNextTime );
xProcessedTCPMessage = 0;
}
}
/* See if any socket was planned to be closed. */
vSocketCloseNextTime( NULL );
/* See if any reusable socket needs to go back to 'eTCP_LISTEN' state. */
vSocketListenNextTime( NULL );
#endif /* ipconfigUSE_TCP == 1 */
}
/*-----------------------------------------------------------*/
/**
* @brief Start an IP timer. The IP-task has its own implementation of a timer
* called 'IPTimer_t', which is based on the FreeRTOS 'TimeOut_t'.
*
* @param[in] pxTimer: Pointer to the IP timer. When zero, the timer is marked
* as expired.
* @param[in] xTime: Time to be loaded into the IP timer.
*/
static void prvIPTimerStart( IPTimer_t * pxTimer,
TickType_t xTime )
{
vTaskSetTimeOutState( &pxTimer->xTimeOut );
pxTimer->ulRemainingTime = xTime;
if( xTime == ( TickType_t ) 0 )
{
pxTimer->bExpired = pdTRUE_UNSIGNED;
}
else
{
pxTimer->bExpired = pdFALSE_UNSIGNED;
}
pxTimer->bActive = pdTRUE_UNSIGNED;
}
/*-----------------------------------------------------------*/
void vIPTimerStartARPResolution( TickType_t xTime )
{
prvIPTimerStart( &( xARPResolutionTimer ), xTime );
}
/*-----------------------------------------------------------*/
/**
* @brief Sets the reload time of an IP timer and restarts it.
*
* @param[in] pxTimer: Pointer to the IP timer.
* @param[in] xTime: Time to be reloaded into the IP timer.
*/
static void prvIPTimerReload( IPTimer_t * pxTimer,
TickType_t xTime )
{
pxTimer->ulReloadTime = xTime;
prvIPTimerStart( pxTimer, xTime );
}
/*-----------------------------------------------------------*/
#if ( ipconfigUSE_TCP == 1 )
void vTCPTimerReload( TickType_t xTime )
{
prvIPTimerReload( &xTCPTimer, xTime );
}
#endif
/*-----------------------------------------------------------*/
void vARPTimerReload( TickType_t xTime )
{
prvIPTimerReload( &xARPTimer, xTime );
}
/*-----------------------------------------------------------*/
#if ( ipconfigUSE_DHCP == 1 )
/**
* @brief Reload the DHCP timer.
*
* @param[in] ulLeaseTime: The reload value.
*/
void vDHCPTimerReload( TickType_t xLeaseTime )
{
prvIPTimerReload( &xDHCPTimer, xLeaseTime );
}
#endif /* ipconfigUSE_DHCP */
/*-----------------------------------------------------------*/
#if ( ipconfigDNS_USE_CALLBACKS != 0 )
/**
* @brief Reload the DNS timer.
*
* @param[in] ulCheckTime: The reload value.
*/
void vDNSTimerReload( uint32_t ulCheckTime )
{
prvIPTimerReload( &xDNSTimer, ulCheckTime );
}
#endif /* ipconfigDNS_USE_CALLBACKS != 0 */
/*-----------------------------------------------------------*/
/**
* @brief Check the IP timer to see whether an IP event should be processed or not.
*
* @param[in] pxTimer: Pointer to the IP timer.
*
* @return If the timer is expired then pdTRUE is returned. Else pdFALSE.
*/
static BaseType_t prvIPTimerCheck( IPTimer_t * pxTimer )
{
BaseType_t xReturn;
if( pxTimer->bActive == pdFALSE_UNSIGNED )
{
/* The timer is not enabled. */
xReturn = pdFALSE;
}
else
{
/* The timer might have set the bExpired flag already, if not, check the
* value of xTimeOut against ulRemainingTime. */
if( pxTimer->bExpired == pdFALSE_UNSIGNED )
{
if( xTaskCheckForTimeOut( &( pxTimer->xTimeOut ), &( pxTimer->ulRemainingTime ) ) != pdFALSE )
{
pxTimer->bExpired = pdTRUE_UNSIGNED;
}
}
if( pxTimer->bExpired != pdFALSE_UNSIGNED )
{
prvIPTimerStart( pxTimer, pxTimer->ulReloadTime );
xReturn = pdTRUE;
}
else
{
xReturn = pdFALSE;
}
}
return xReturn;
}
/*-----------------------------------------------------------*/
#if ( ipconfigUSE_TCP == 1 )
/**
* @brief Enable/disable the TCP timer.
*
* @param[in] xExpiredState: pdTRUE - set as expired; pdFALSE - set as non-expired.
*/
void vIPSetTCPTimerExpiredState( BaseType_t xExpiredState )
{
xTCPTimer.bActive = pdTRUE_UNSIGNED;
if( xExpiredState != pdFALSE )
{
xTCPTimer.bExpired = pdTRUE_UNSIGNED;
}
else
{
xTCPTimer.bExpired = pdFALSE_UNSIGNED;
}
}
/*-----------------------------------------------------------*/
#endif /* if ( ipconfigUSE_TCP == 1 ) */
/**
* @brief Enable/disable the ARP timer.
*
* @param[in] xEnableState: pdTRUE - enable timer; pdFALSE - disable timer.
*/
void vIPSetARPTimerEnableState( BaseType_t xEnableState )
{
if( xEnableState != pdFALSE )
{
xARPTimer.bActive = pdTRUE_UNSIGNED;
}
else
{
xARPTimer.bActive = pdFALSE_UNSIGNED;
}
}
/*-----------------------------------------------------------*/
/**
* @brief Enable or disable the ARP resolution timer.
*
* @param[in] xEnableState: pdTRUE if the timer must be enabled, pdFALSE otherwise.
*/
void vIPSetARPResolutionTimerEnableState( BaseType_t xEnableState )
{
if( xEnableState != pdFALSE )
{
xARPResolutionTimer.bActive = pdTRUE_UNSIGNED;
}
else
{
xARPResolutionTimer.bActive = pdFALSE_UNSIGNED;
}
}
/*-----------------------------------------------------------*/
#if ( ipconfigUSE_DHCP == 1 )
/**
* @brief Enable/disable the DHCP timer.
*
* @param[in] xEnableState: pdTRUE - enable timer; pdFALSE - disable timer.
*/
void vIPSetDHCPTimerEnableState( BaseType_t xEnableState )
{
if( xEnableState != pdFALSE )
{
xDHCPTimer.bActive = pdTRUE_UNSIGNED;
}
else
{
xDHCPTimer.bActive = pdFALSE_UNSIGNED;
}
}
#endif /* ipconfigUSE_DHCP */
/*-----------------------------------------------------------*/
#if ( ipconfigDNS_USE_CALLBACKS == 1 )
/**
* @brief Enable/disable the DNS timer.
*
* @param[in] xEnableState: pdTRUE - enable timer; pdFALSE - disable timer.
*/
void vIPSetDNSTimerEnableState( BaseType_t xEnableState )
{
if( xEnableState != 0 )
{
xDNSTimer.bActive = pdTRUE_UNSIGNED;
}
else
{
xDNSTimer.bActive = pdFALSE_UNSIGNED;
}
}
#endif /* ipconfigDNS_USE_CALLBACKS == 1 */
/*-----------------------------------------------------------*/