X-Git-Url: https://git.sur5r.net/?p=freertos;a=blobdiff_plain;f=FreeRTOS-Plus%2FSource%2FFreeRTOS-Plus-TCP%2FFreeRTOS_Sockets.c;fp=FreeRTOS-Plus%2FSource%2FFreeRTOS-Plus-TCP%2FFreeRTOS_Sockets.c;h=87099ecf15abf9076bfb92609ed49a83ea6632e3;hp=e15834849ef2dd590f8671223d17e3d639a13dc8;hb=b15dfacb6026af3b0ba697e5753844923b468d2b;hpb=4334233a064299a09d167a497889d3860932a587 diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_Sockets.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_Sockets.c index e15834849..87099ecf1 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_Sockets.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_Sockets.c @@ -1,3675 +1,3675 @@ -/* - * FreeRTOS+TCP V2.2.0 - * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * 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 - */ - -/* Standard includes. */ -#include -#include - -/* FreeRTOS includes. */ -#include "FreeRTOS.h" -#include "task.h" -#include "queue.h" -#include "semphr.h" - -/* FreeRTOS+TCP includes. */ -#include "FreeRTOS_UDP_IP.h" -#include "FreeRTOS_IP.h" -#include "FreeRTOS_Sockets.h" -#include "FreeRTOS_IP_Private.h" -#include "FreeRTOS_DNS.h" -#include "NetworkBufferManagement.h" - -/* The ItemValue of the sockets xBoundSocketListItem member holds the socket's -port number. */ -#define socketSET_SOCKET_PORT( pxSocket, usPort ) listSET_LIST_ITEM_VALUE( ( &( ( pxSocket )->xBoundSocketListItem ) ), ( usPort ) ) -#define socketGET_SOCKET_PORT( pxSocket ) listGET_LIST_ITEM_VALUE( ( &( ( pxSocket )->xBoundSocketListItem ) ) ) - -/* Test if a socket it bound which means it is either included in -xBoundUDPSocketsList or xBoundTCPSocketsList */ -#define socketSOCKET_IS_BOUND( pxSocket ) ( listLIST_ITEM_CONTAINER( & ( pxSocket )->xBoundSocketListItem ) != NULL ) - -/* If FreeRTOS_sendto() is called on a socket that is not bound to a port -number then, depending on the FreeRTOSIPConfig.h settings, it might be that a -port number is automatically generated for the socket. Automatically generated -port numbers will be between socketAUTO_PORT_ALLOCATION_START_NUMBER and -0xffff. - -Per https://tools.ietf.org/html/rfc6056, "the dynamic ports consist of the range -49152-65535. However, ephemeral port selection algorithms should use the whole -range 1024-65535" excluding those already in use (inbound or outbound). */ -#if !defined( socketAUTO_PORT_ALLOCATION_START_NUMBER ) - #define socketAUTO_PORT_ALLOCATION_START_NUMBER ( ( uint16_t ) 0x0400 ) -#endif - -#define socketAUTO_PORT_ALLOCATION_MAX_NUMBER ( ( uint16_t ) 0xffff ) - -/* The number of octets that make up an IP address. */ -#define socketMAX_IP_ADDRESS_OCTETS 4u - -/* A block time of 0 simply means "don't block". */ -#define socketDONT_BLOCK ( ( TickType_t ) 0 ) - -#if( ( ipconfigUSE_TCP == 1 ) && !defined( ipTCP_TIMER_PERIOD_MS ) ) - #define ipTCP_TIMER_PERIOD_MS ( 1000 ) -#endif - -/* The next private port number to use when binding a client socket is stored in -the usNextPortToUse[] array - which has either 1 or two indexes depending on -whether TCP is being supported. */ -#if( ipconfigUSE_TCP == 1 ) - #define socketPROTOCOL_COUNT 2 -#else - #define socketPROTOCOL_COUNT 1 -#endif - -/* Indexes into the usNextPortToUse[] array for UDP and TCP sockets -respectively. */ -#define socketNEXT_UDP_PORT_NUMBER_INDEX 0 -#define socketNEXT_TCP_PORT_NUMBER_INDEX 1 - -/* Some helper macro's for defining the 20/80 % limits of uxLittleSpace / uxEnoughSpace. */ -#define sock20_PERCENT 20 -#define sock80_PERCENT 80 -#define sock100_PERCENT 100 - - -/*-----------------------------------------------------------*/ - -/* - * Allocate the next port number from the private allocation range. - * TCP and UDP each have their own series of port numbers - * ulProtocol is either ipPROTOCOL_UDP or ipPROTOCOL_TCP - */ -static uint16_t prvGetPrivatePortNumber( BaseType_t xProtocol ); - -/* - * Return the list item from within pxList that has an item value of - * xWantedItemValue. If there is no such list item return NULL. - */ -static const ListItem_t * pxListFindListItemWithValue( const List_t *pxList, TickType_t xWantedItemValue ); - -/* - * Return pdTRUE only if pxSocket is valid and bound, as far as can be - * determined. - */ -static BaseType_t prvValidSocket( FreeRTOS_Socket_t *pxSocket, BaseType_t xProtocol, BaseType_t xIsBound ); - -/* - * Before creating a socket, check the validity of the parameters used - * and find the size of the socket space, which is different for UDP and TCP - */ -static BaseType_t prvDetermineSocketSize( BaseType_t xDomain, BaseType_t xType, BaseType_t xProtocol, size_t *pxSocketSize ); - -#if( ipconfigUSE_TCP == 1 ) - /* - * Create a txStream or a rxStream, depending on the parameter 'xIsInputStream' - */ - static StreamBuffer_t *prvTCPCreateStream (FreeRTOS_Socket_t *pxSocket, BaseType_t xIsInputStream ); -#endif /* ipconfigUSE_TCP == 1 */ - -#if( ipconfigUSE_TCP == 1 ) - /* - * Called from FreeRTOS_send(): some checks which will be done before - * sending a TCP packed. - */ - static int32_t prvTCPSendCheck( FreeRTOS_Socket_t *pxSocket, size_t xDataLength ); -#endif /* ipconfigUSE_TCP */ - -#if( ipconfigUSE_TCP == 1 ) - /* - * When a child socket gets closed, make sure to update the child-count of the parent - */ - static void prvTCPSetSocketCount( FreeRTOS_Socket_t *pxSocketToDelete ); -#endif /* ipconfigUSE_TCP == 1 */ - -#if( ipconfigUSE_TCP == 1 ) - /* - * Called from FreeRTOS_connect(): make some checks and if allowed, send a - * message to the IP-task to start connecting to a remote socket - */ - static BaseType_t prvTCPConnectStart( FreeRTOS_Socket_t *pxSocket, struct freertos_sockaddr *pxAddress ); -#endif /* ipconfigUSE_TCP */ - -#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) - - /* Executed by the IP-task, it will check all sockets belonging to a set */ - static FreeRTOS_Socket_t *prvFindSelectedSocket( SocketSelect_t *pxSocketSet ); - -#endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */ -/*-----------------------------------------------------------*/ - -/* The list that contains mappings between sockets and port numbers. Accesses -to this list must be protected by critical sections of one kind or another. */ -List_t xBoundUDPSocketsList; - -#if ipconfigUSE_TCP == 1 - List_t xBoundTCPSocketsList; -#endif /* ipconfigUSE_TCP == 1 */ - -/*-----------------------------------------------------------*/ - -static BaseType_t prvValidSocket( FreeRTOS_Socket_t *pxSocket, BaseType_t xProtocol, BaseType_t xIsBound ) -{ -BaseType_t xReturn = pdTRUE; - - if( ( pxSocket == NULL ) || ( pxSocket == FREERTOS_INVALID_SOCKET ) ) - { - xReturn = pdFALSE; - } - else if( ( xIsBound != pdFALSE ) && ( socketSOCKET_IS_BOUND( pxSocket ) == pdFALSE ) ) - { - /* The caller expects the socket to be bound, but it isn't. */ - xReturn = pdFALSE; - } - else if( pxSocket->ucProtocol != ( uint8_t ) xProtocol ) - { - /* Socket has a wrong type (UDP != TCP). */ - xReturn = pdFALSE; - } - - return xReturn; -} -/*-----------------------------------------------------------*/ - -BaseType_t vNetworkSocketsInit( void ) -{ - vListInitialise( &xBoundUDPSocketsList ); - - #if( ipconfigUSE_TCP == 1 ) - { - vListInitialise( &xBoundTCPSocketsList ); - } - #endif /* ipconfigUSE_TCP == 1 */ - - return pdTRUE; -} -/*-----------------------------------------------------------*/ - -static BaseType_t prvDetermineSocketSize( BaseType_t xDomain, BaseType_t xType, BaseType_t xProtocol, size_t *pxSocketSize ) -{ -BaseType_t xReturn = pdPASS; -FreeRTOS_Socket_t *pxSocket; - - /* Asserts must not appear before it has been determined that the network - task is ready - otherwise the asserts will fail. */ - if( xIPIsNetworkTaskReady() == pdFALSE ) - { - xReturn = pdFAIL; - } - else - { - /* Only Ethernet is currently supported. */ - configASSERT( xDomain == FREERTOS_AF_INET ); - - /* Check if the UDP socket-list has been initialised. */ - configASSERT( listLIST_IS_INITIALISED( &xBoundUDPSocketsList ) ); - #if( ipconfigUSE_TCP == 1 ) - { - /* Check if the TCP socket-list has been initialised. */ - configASSERT( listLIST_IS_INITIALISED( &xBoundTCPSocketsList ) ); - } - #endif /* ipconfigUSE_TCP == 1 */ - - if( xProtocol == FREERTOS_IPPROTO_UDP ) - { - if( xType != FREERTOS_SOCK_DGRAM ) - { - xReturn = pdFAIL; - configASSERT( xReturn ); - } - /* In case a UDP socket is created, do not allocate space for TCP data. */ - *pxSocketSize = ( sizeof( *pxSocket ) - sizeof( pxSocket->u ) ) + sizeof( pxSocket->u.xUDP ); - } -#if( ipconfigUSE_TCP == 1 ) - else if( xProtocol == FREERTOS_IPPROTO_TCP ) - { - if( xType != FREERTOS_SOCK_STREAM ) - { - xReturn = pdFAIL; - configASSERT( xReturn ); - } - - *pxSocketSize = ( sizeof( *pxSocket ) - sizeof( pxSocket->u ) ) + sizeof( pxSocket->u.xTCP ); - } -#endif /* ipconfigUSE_TCP == 1 */ - else - { - xReturn = pdFAIL; - configASSERT( xReturn ); - } - } - /* In case configASSERT() is not used */ - ( void )xDomain; - return xReturn; -} -/*-----------------------------------------------------------*/ - -/* FreeRTOS_socket() allocates and initiates a socket */ -Socket_t FreeRTOS_socket( BaseType_t xDomain, BaseType_t xType, BaseType_t xProtocol ) -{ -FreeRTOS_Socket_t *pxSocket; -size_t uxSocketSize; -EventGroupHandle_t xEventGroup; -Socket_t xReturn; - - if( prvDetermineSocketSize( xDomain, xType, xProtocol, &uxSocketSize ) == pdFAIL ) - { - xReturn = FREERTOS_INVALID_SOCKET; - } - else - { - /* Allocate the structure that will hold the socket information. The - size depends on the type of socket: UDP sockets need less space. A - define 'pvPortMallocSocket' will used to allocate the necessary space. - By default it points to the FreeRTOS function 'pvPortMalloc()'. */ - pxSocket = ( FreeRTOS_Socket_t * ) pvPortMallocSocket( uxSocketSize ); - - if( pxSocket == NULL ) - { - pxSocket = ( FreeRTOS_Socket_t * ) FREERTOS_INVALID_SOCKET; - iptraceFAILED_TO_CREATE_SOCKET(); - } - else if( ( xEventGroup = xEventGroupCreate() ) == NULL ) - { - vPortFreeSocket( pxSocket ); - pxSocket = ( FreeRTOS_Socket_t * ) FREERTOS_INVALID_SOCKET; - iptraceFAILED_TO_CREATE_EVENT_GROUP(); - } - else - { - /* Clear the entire space to avoid nulling individual entries */ - memset( pxSocket, '\0', uxSocketSize ); - - pxSocket->xEventGroup = xEventGroup; - - /* Initialise the socket's members. The semaphore will be created - if the socket is bound to an address, for now the pointer to the - semaphore is just set to NULL to show it has not been created. */ - if( xProtocol == FREERTOS_IPPROTO_UDP ) - { - vListInitialise( &( pxSocket->u.xUDP.xWaitingPacketsList ) ); - - #if( ipconfigUDP_MAX_RX_PACKETS > 0 ) - { - pxSocket->u.xUDP.uxMaxPackets = ( UBaseType_t ) ipconfigUDP_MAX_RX_PACKETS; - } - #endif /* ipconfigUDP_MAX_RX_PACKETS > 0 */ - } - - vListInitialiseItem( &( pxSocket->xBoundSocketListItem ) ); - listSET_LIST_ITEM_OWNER( &( pxSocket->xBoundSocketListItem ), ( void * ) pxSocket ); - - pxSocket->xReceiveBlockTime = ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME; - pxSocket->xSendBlockTime = ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME; - pxSocket->ucSocketOptions = ( uint8_t ) FREERTOS_SO_UDPCKSUM_OUT; - pxSocket->ucProtocol = ( uint8_t ) xProtocol; /* protocol: UDP or TCP */ - - #if( ipconfigUSE_TCP == 1 ) - { - if( xProtocol == FREERTOS_IPPROTO_TCP ) - { - /* StreamSize is expressed in number of bytes */ - /* Round up buffer sizes to nearest multiple of MSS */ - pxSocket->u.xTCP.usInitMSS = pxSocket->u.xTCP.usCurMSS = ipconfigTCP_MSS; - pxSocket->u.xTCP.uxRxStreamSize = ( size_t ) ipconfigTCP_RX_BUFFER_LENGTH; - pxSocket->u.xTCP.uxTxStreamSize = ( size_t ) FreeRTOS_round_up( ipconfigTCP_TX_BUFFER_LENGTH, ipconfigTCP_MSS ); - /* Use half of the buffer size of the TCP windows */ - #if ( ipconfigUSE_TCP_WIN == 1 ) - { - pxSocket->u.xTCP.uxRxWinSize = FreeRTOS_max_uint32( 1UL, ( uint32_t ) ( pxSocket->u.xTCP.uxRxStreamSize / 2 ) / ipconfigTCP_MSS ); - pxSocket->u.xTCP.uxTxWinSize = FreeRTOS_max_uint32( 1UL, ( uint32_t ) ( pxSocket->u.xTCP.uxTxStreamSize / 2 ) / ipconfigTCP_MSS ); - } - #else - { - pxSocket->u.xTCP.uxRxWinSize = 1u; - pxSocket->u.xTCP.uxTxWinSize = 1u; - } - #endif - /* The above values are just defaults, and can be overridden by - calling FreeRTOS_setsockopt(). No buffers will be allocated until a - socket is connected and data is exchanged. */ - } - } - #endif /* ipconfigUSE_TCP == 1 */ - } - - xReturn = ( Socket_t ) pxSocket; - } - - /* Remove compiler warnings in the case the configASSERT() is not defined. */ - ( void ) xDomain; - - return xReturn; -} -/*-----------------------------------------------------------*/ - -#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) - - SocketSet_t FreeRTOS_CreateSocketSet( void ) - { - SocketSelect_t *pxSocketSet; - - pxSocketSet = ( SocketSelect_t * ) pvPortMalloc( sizeof( *pxSocketSet ) ); - - if( pxSocketSet != NULL ) - { - memset( pxSocketSet, '\0', sizeof( *pxSocketSet ) ); - pxSocketSet->xSelectGroup = xEventGroupCreate(); - - if( pxSocketSet->xSelectGroup == NULL ) - { - vPortFree( ( void* ) pxSocketSet ); - pxSocketSet = NULL; - } - } - - return ( SocketSet_t ) pxSocketSet; - } - -#endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */ -/*-----------------------------------------------------------*/ - -#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) - - void FreeRTOS_DeleteSocketSet( SocketSet_t xSocketSet ) - { - SocketSelect_t *pxSocketSet = ( SocketSelect_t*) xSocketSet; - - vEventGroupDelete( pxSocketSet->xSelectGroup ); - vPortFree( ( void* ) pxSocketSet ); - } - -#endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */ -/*-----------------------------------------------------------*/ - -#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) - - /* Add a socket to a set */ - void FreeRTOS_FD_SET( Socket_t xSocket, SocketSet_t xSocketSet, EventBits_t xSelectBits ) - { - FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; - SocketSelect_t *pxSocketSet = ( SocketSelect_t * ) xSocketSet; - - configASSERT( pxSocket != NULL ); - configASSERT( xSocketSet != NULL ); - - /* Make sure we're not adding bits which are reserved for internal use, - such as eSELECT_CALL_IP */ - pxSocket->xSelectBits |= ( xSelectBits & eSELECT_ALL ); - - if( ( pxSocket->xSelectBits & eSELECT_ALL ) != 0 ) - { - /* Adding a socket to a socket set. */ - pxSocket->pxSocketSet = ( SocketSelect_t * ) xSocketSet; - - /* Now have the IP-task call vSocketSelect() to see if the set contains - any sockets which are 'ready' and set the proper bits. - By setting 'bApiCalled = false', vSocketSelect() knows that it was - not called from a user API */ - pxSocketSet->bApiCalled = pdFALSE; - prvFindSelectedSocket( pxSocketSet ); - } - } - -#endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */ -/*-----------------------------------------------------------*/ - -#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) - /* Clear select bits for a socket - If the mask becomes 0, remove the socket from the set */ - void FreeRTOS_FD_CLR( Socket_t xSocket, SocketSet_t xSocketSet, EventBits_t xSelectBits ) - { - FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; - - configASSERT( pxSocket != NULL ); - configASSERT( xSocketSet != NULL ); - - pxSocket->xSelectBits &= ~( xSelectBits & eSELECT_ALL ); - if( ( pxSocket->xSelectBits & eSELECT_ALL ) != 0 ) - { - pxSocket->pxSocketSet = ( SocketSelect_t *)xSocketSet; - } - else - { - /* disconnect it from the socket set */ - pxSocket->pxSocketSet = ( SocketSelect_t *)NULL; - } - } - -#endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */ -/*-----------------------------------------------------------*/ - - -#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) - - /* Test if a socket belongs to a socket-set */ - EventBits_t FreeRTOS_FD_ISSET( Socket_t xSocket, SocketSet_t xSocketSet ) - { - EventBits_t xReturn; - FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; - - configASSERT( pxSocket != NULL ); - configASSERT( xSocketSet != NULL ); - - if( xSocketSet == ( SocketSet_t ) pxSocket->pxSocketSet ) - { - /* Make sure we're not adding bits which are reserved for internal - use. */ - xReturn = pxSocket->xSocketBits & eSELECT_ALL; - } - else - { - xReturn = 0; - } - - return xReturn; - } - -#endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */ -/*-----------------------------------------------------------*/ - -#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) - - /* The select() statement: wait for an event to occur on any of the sockets - included in a socket set */ - BaseType_t FreeRTOS_select( SocketSet_t xSocketSet, TickType_t xBlockTimeTicks ) - { - TimeOut_t xTimeOut; - TickType_t xRemainingTime; - SocketSelect_t *pxSocketSet = ( SocketSelect_t*) xSocketSet; - BaseType_t xResult; - - configASSERT( xSocketSet != NULL ); - - /* Only in the first round, check for non-blocking */ - xRemainingTime = xBlockTimeTicks; - - /* Fetch the current time */ - vTaskSetTimeOutState( &xTimeOut ); - - for( ;; ) - { - /* Find a socket which might have triggered the bit - This function might return immediately or block for a limited time */ - xResult = ( BaseType_t ) xEventGroupWaitBits( pxSocketSet->xSelectGroup, eSELECT_ALL, pdFALSE, pdFALSE, xRemainingTime ); - - #if( ipconfigSUPPORT_SIGNALS != 0 ) - { - if( ( xResult & eSELECT_INTR ) != 0u ) - { - xEventGroupClearBits( pxSocketSet->xSelectGroup, eSELECT_INTR ); - FreeRTOS_debug_printf( ( "FreeRTOS_select: interrupted\n" ) ); - break; - } - } - #endif /* ipconfigSUPPORT_SIGNALS */ - - /* Have the IP-task find the socket which had an event */ - pxSocketSet->bApiCalled = pdTRUE; - prvFindSelectedSocket( pxSocketSet ); - - xResult = ( BaseType_t ) xEventGroupGetBits( pxSocketSet->xSelectGroup ); - - if( xResult != 0 ) - { - break; - } - - /* Has the timeout been reached? */ - if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE ) - { - break; - } - } - - return xResult; - } - -#endif /* ipconfigSUPPORT_SELECT_FUNCTION */ -/*-----------------------------------------------------------*/ - -#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) - - /* Send a message to the IP-task to have it check all sockets belonging to - 'pxSocketSet' */ - static FreeRTOS_Socket_t *prvFindSelectedSocket( SocketSelect_t *pxSocketSet ) - { - IPStackEvent_t xSelectEvent; - FreeRTOS_Socket_t *xReturn; - - xSelectEvent.eEventType = eSocketSelectEvent; - xSelectEvent.pvData = ( void * ) pxSocketSet; - - /* while the IP-task works on the request, the API will block on - 'eSELECT_CALL_IP'. So clear it first. */ - xEventGroupClearBits( pxSocketSet->xSelectGroup, eSELECT_CALL_IP ); - - /* Now send the socket select event */ - if( xSendEventStructToIPTask( &xSelectEvent, ( TickType_t ) portMAX_DELAY ) == pdFAIL ) - { - /* Oops, we failed to wake-up the IP task. No use to wait for it. */ - FreeRTOS_debug_printf( ( "prvFindSelectedSocket: failed\n" ) ); - xReturn = NULL; - } - else - { - /* As soon as the IP-task is ready, it will set 'eSELECT_CALL_IP' to - wakeup the calling API */ - xEventGroupWaitBits( pxSocketSet->xSelectGroup, eSELECT_CALL_IP, pdTRUE, pdFALSE, portMAX_DELAY ); - - /* Return 'pxSocket' which is set by the IP-task */ - xReturn = pxSocketSet->pxSocket; - } - - return xReturn; - } - -#endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */ -/*-----------------------------------------------------------*/ - -/* - * FreeRTOS_recvfrom: receive data from a bound socket - * In this library, the function can only be used with connectionsless sockets - * (UDP) - */ -int32_t FreeRTOS_recvfrom( Socket_t xSocket, void *pvBuffer, size_t xBufferLength, BaseType_t xFlags, struct freertos_sockaddr *pxSourceAddress, socklen_t *pxSourceAddressLength ) -{ -BaseType_t lPacketCount = 0; -NetworkBufferDescriptor_t *pxNetworkBuffer; -FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; -TickType_t xRemainingTime = ( TickType_t ) 0; /* Obsolete assignment, but some compilers output a warning if its not done. */ -BaseType_t xTimed = pdFALSE; -TimeOut_t xTimeOut; -int32_t lReturn; -EventBits_t xEventBits = ( EventBits_t ) 0; - - if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_UDP, pdTRUE ) == pdFALSE ) - { - return -pdFREERTOS_ERRNO_EINVAL; - } - - lPacketCount = ( BaseType_t ) listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ); - - /* The function prototype is designed to maintain the expected Berkeley - sockets standard, but this implementation does not use all the parameters. */ - ( void ) pxSourceAddressLength; - - while( lPacketCount == 0 ) - { - if( xTimed == pdFALSE ) - { - /* Check to see if the socket is non blocking on the first - iteration. */ - xRemainingTime = pxSocket->xReceiveBlockTime; - - if( xRemainingTime == ( TickType_t ) 0 ) - { - #if( ipconfigSUPPORT_SIGNALS != 0 ) - { - /* Just check for the interrupt flag. */ - xEventBits = xEventGroupWaitBits( pxSocket->xEventGroup, eSOCKET_INTR, - pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, socketDONT_BLOCK ); - } - #endif /* ipconfigSUPPORT_SIGNALS */ - break; - } - - if( ( xFlags & FREERTOS_MSG_DONTWAIT ) != 0 ) - { - break; - } - - /* To ensure this part only executes once. */ - xTimed = pdTRUE; - - /* Fetch the current time. */ - vTaskSetTimeOutState( &xTimeOut ); - } - - /* Wait for arrival of data. While waiting, the IP-task may set the - 'eSOCKET_RECEIVE' bit in 'xEventGroup', if it receives data for this - socket, thus unblocking this API call. */ - xEventBits = xEventGroupWaitBits( pxSocket->xEventGroup, eSOCKET_RECEIVE | eSOCKET_INTR, - pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime ); - - #if( ipconfigSUPPORT_SIGNALS != 0 ) - { - if( ( xEventBits & eSOCKET_INTR ) != 0 ) - { - if( ( xEventBits & eSOCKET_RECEIVE ) != 0 ) - { - /* Shouldn't have cleared the eSOCKET_RECEIVE flag. */ - xEventGroupSetBits( pxSocket->xEventGroup, eSOCKET_RECEIVE ); - } - break; - } - } - #else - { - ( void ) xEventBits; - } - #endif /* ipconfigSUPPORT_SIGNALS */ - - lPacketCount = ( BaseType_t ) listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ); - - if( lPacketCount != 0 ) - { - break; - } - - /* Has the timeout been reached ? */ - if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) ) - { - break; - } - } /* while( lPacketCount == 0 ) */ - - if( lPacketCount != 0 ) - { - taskENTER_CRITICAL(); - { - /* The owner of the list item is the network buffer. */ - pxNetworkBuffer = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->u.xUDP.xWaitingPacketsList ) ); - - if( ( xFlags & FREERTOS_MSG_PEEK ) == 0 ) - { - /* Remove the network buffer from the list of buffers waiting to - be processed by the socket. */ - uxListRemove( &( pxNetworkBuffer->xBufferListItem ) ); - } - } - taskEXIT_CRITICAL(); - - /* The returned value is the length of the payload data, which is - calculated at the total packet size minus the headers. - The validity of `xDataLength` prvProcessIPPacket has been confirmed - in 'prvProcessIPPacket()'. */ - lReturn = ( int32_t ) ( pxNetworkBuffer->xDataLength - sizeof( UDPPacket_t ) ); - - if( pxSourceAddress != NULL ) - { - pxSourceAddress->sin_port = pxNetworkBuffer->usPort; - pxSourceAddress->sin_addr = pxNetworkBuffer->ulIPAddress; - } - - if( ( xFlags & FREERTOS_ZERO_COPY ) == 0 ) - { - /* The zero copy flag is not set. Truncate the length if it won't - fit in the provided buffer. */ - if( lReturn > ( int32_t ) xBufferLength ) - { - iptraceRECVFROM_DISCARDING_BYTES( ( xBufferLength - lReturn ) ); - lReturn = ( int32_t )xBufferLength; - } - - /* Copy the received data into the provided buffer, then release the - network buffer. */ - memcpy( pvBuffer, ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] ), ( size_t )lReturn ); - - if( ( xFlags & FREERTOS_MSG_PEEK ) == 0 ) - { - vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); - } - } - else - { - /* The zero copy flag was set. pvBuffer is not a buffer into which - the received data can be copied, but a pointer that must be set to - point to the buffer in which the received data has already been - placed. */ - *( ( void** ) pvBuffer ) = ( void * ) ( &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] ) ); - } - - } -#if( ipconfigSUPPORT_SIGNALS != 0 ) - else if( ( xEventBits & eSOCKET_INTR ) != 0 ) - { - lReturn = -pdFREERTOS_ERRNO_EINTR; - iptraceRECVFROM_INTERRUPTED(); - } -#endif /* ipconfigSUPPORT_SIGNALS */ - else - { - lReturn = -pdFREERTOS_ERRNO_EWOULDBLOCK; - iptraceRECVFROM_TIMEOUT(); - } - - return lReturn; -} -/*-----------------------------------------------------------*/ - -int32_t FreeRTOS_sendto( Socket_t xSocket, const void *pvBuffer, size_t xTotalDataLength, BaseType_t xFlags, const struct freertos_sockaddr *pxDestinationAddress, socklen_t xDestinationAddressLength ) -{ -NetworkBufferDescriptor_t *pxNetworkBuffer; -IPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL }; -TimeOut_t xTimeOut; -TickType_t xTicksToWait; -int32_t lReturn = 0; -FreeRTOS_Socket_t *pxSocket; - - pxSocket = ( FreeRTOS_Socket_t * ) xSocket; - - /* The function prototype is designed to maintain the expected Berkeley - sockets standard, but this implementation does not use all the - parameters. */ - ( void ) xDestinationAddressLength; - configASSERT( pvBuffer ); - - if( xTotalDataLength <= ( size_t ) ipMAX_UDP_PAYLOAD_LENGTH ) - { - /* If the socket is not already bound to an address, bind it now. - Passing NULL as the address parameter tells FreeRTOS_bind() to select - the address to bind to. */ - if( ( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE ) || - ( FreeRTOS_bind( xSocket, NULL, 0u ) == 0 ) ) - { - xTicksToWait = pxSocket->xSendBlockTime; - - #if( ipconfigUSE_CALLBACKS != 0 ) - { - if( xIsCallingFromIPTask() != pdFALSE ) - { - /* If this send function is called from within a call-back - handler it may not block, otherwise chances would be big to - get a deadlock: the IP-task waiting for itself. */ - xTicksToWait = ( TickType_t )0; - } - } - #endif /* ipconfigUSE_CALLBACKS */ - - if( ( xFlags & FREERTOS_MSG_DONTWAIT ) != 0 ) - { - xTicksToWait = ( TickType_t ) 0; - } - - if( ( xFlags & FREERTOS_ZERO_COPY ) == 0 ) - { - /* Zero copy is not set, so obtain a network buffer into - which the payload will be copied. */ - vTaskSetTimeOutState( &xTimeOut ); - - /* Block until a buffer becomes available, or until a - timeout has been reached */ - pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( xTotalDataLength + sizeof( UDPPacket_t ), xTicksToWait ); - - if( pxNetworkBuffer != NULL ) - { - memcpy( ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] ), ( void * ) pvBuffer, xTotalDataLength ); - - if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdTRUE ) - { - /* The entire block time has been used up. */ - xTicksToWait = ( TickType_t ) 0; - } - } - } - else - { - /* When zero copy is used, pvBuffer is a pointer to the - payload of a buffer that has already been obtained from the - stack. Obtain the network buffer pointer from the buffer. */ - pxNetworkBuffer = pxUDPPayloadBuffer_to_NetworkBuffer( (void*)pvBuffer ); - } - - if( pxNetworkBuffer != NULL ) - { - /* xDataLength is the size of the total packet, including the Ethernet header. */ - pxNetworkBuffer->xDataLength = xTotalDataLength + sizeof( UDPPacket_t ); - pxNetworkBuffer->usPort = pxDestinationAddress->sin_port; - pxNetworkBuffer->usBoundPort = ( uint16_t ) socketGET_SOCKET_PORT( pxSocket ); - pxNetworkBuffer->ulIPAddress = pxDestinationAddress->sin_addr; - - /* The socket options are passed to the IP layer in the - space that will eventually get used by the Ethernet header. */ - pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] = pxSocket->ucSocketOptions; - - /* Tell the networking task that the packet needs sending. */ - xStackTxEvent.pvData = pxNetworkBuffer; - - /* Ask the IP-task to send this packet */ - if( xSendEventStructToIPTask( &xStackTxEvent, xTicksToWait ) == pdPASS ) - { - /* The packet was successfully sent to the IP task. */ - lReturn = ( int32_t ) xTotalDataLength; - #if( ipconfigUSE_CALLBACKS == 1 ) - { - if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xUDP.pxHandleSent ) ) - { - pxSocket->u.xUDP.pxHandleSent( ( Socket_t )pxSocket, xTotalDataLength ); - } - } - #endif /* ipconfigUSE_CALLBACKS */ - } - else - { - /* If the buffer was allocated in this function, release - it. */ - if( ( xFlags & FREERTOS_ZERO_COPY ) == 0 ) - { - vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); - } - iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT ); - } - } - else - { - /* If errno was available, errno would be set to - FREERTOS_ENOPKTS. As it is, the function must return the - number of transmitted bytes, so the calling function knows - how much data was actually sent. */ - iptraceNO_BUFFER_FOR_SENDTO(); - } - } - else - { - iptraceSENDTO_SOCKET_NOT_BOUND(); - } - } - else - { - /* The data is longer than the available buffer space. */ - iptraceSENDTO_DATA_TOO_LONG(); - } - - return lReturn; -} /* Tested */ -/*-----------------------------------------------------------*/ - -/* - * FreeRTOS_bind() : binds a sockt to a local port number. If port 0 is - * provided, a system provided port number will be assigned. This function can - * be used for both UDP and TCP sockets. The actual binding will be performed - * by the IP-task to avoid mutual access to the bound-socket-lists - * (xBoundUDPSocketsList or xBoundTCPSocketsList). - */ -BaseType_t FreeRTOS_bind( Socket_t xSocket, struct freertos_sockaddr * pxAddress, socklen_t xAddressLength ) -{ -IPStackEvent_t xBindEvent; -FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; -BaseType_t xReturn = 0; - - ( void ) xAddressLength; - - if( ( pxSocket == NULL ) || ( pxSocket == FREERTOS_INVALID_SOCKET ) ) - { - xReturn = -pdFREERTOS_ERRNO_EINVAL; - } - /* Once a socket is bound to a port, it can not be bound to a different - port number */ - else if( socketSOCKET_IS_BOUND( pxSocket) != pdFALSE ) - { - /* The socket is already bound. */ - FreeRTOS_debug_printf( ( "vSocketBind: Socket already bound to %d\n", pxSocket->usLocalPort ) ); - xReturn = -pdFREERTOS_ERRNO_EINVAL; - } - else - { - /* Prepare a messages to the IP-task in order to perform the binding. - The desired port number will be passed in usLocalPort. */ - xBindEvent.eEventType = eSocketBindEvent; - xBindEvent.pvData = ( void * ) xSocket; - if( pxAddress != NULL ) - { - pxSocket->usLocalPort = FreeRTOS_ntohs( pxAddress->sin_port ); - } - else - { - /* Caller wants to bind to a random port number. */ - pxSocket->usLocalPort = 0u; - } - - /* portMAX_DELAY is used as a the time-out parameter, as binding *must* - succeed before the socket can be used. _RB_ The use of an infinite - block time needs be changed as it could result in the task hanging. */ - if( xSendEventStructToIPTask( &xBindEvent, ( TickType_t ) portMAX_DELAY ) == pdFAIL ) - { - /* Failed to wake-up the IP-task, no use to wait for it */ - FreeRTOS_debug_printf( ( "FreeRTOS_bind: send event failed\n" ) ); - xReturn = -pdFREERTOS_ERRNO_ECANCELED; - } - else - { - /* The IP-task will set the 'eSOCKET_BOUND' bit when it has done its - job. */ - xEventGroupWaitBits( pxSocket->xEventGroup, eSOCKET_BOUND, pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, portMAX_DELAY ); - if( socketSOCKET_IS_BOUND( pxSocket ) == pdFALSE ) - { - xReturn = -pdFREERTOS_ERRNO_EINVAL; - } - } - } - - return xReturn; -} - -/* - * vSocketBind(): internal version of bind() that should not be called directly. - * 'xInternal' is used for TCP sockets only: it allows to have several - * (connected) child sockets bound to the same server port. - */ -BaseType_t vSocketBind( FreeRTOS_Socket_t *pxSocket, struct freertos_sockaddr * pxAddress, size_t uxAddressLength, BaseType_t xInternal ) -{ -BaseType_t xReturn = 0; /* In Berkeley sockets, 0 means pass for bind(). */ -List_t *pxSocketList; -#if( ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 ) - struct freertos_sockaddr xAddress; -#endif /* ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND */ - -#if( ipconfigUSE_TCP == 1 ) - if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP ) - { - pxSocketList = &xBoundTCPSocketsList; - } - else -#endif /* ipconfigUSE_TCP == 1 */ - { - pxSocketList = &xBoundUDPSocketsList; - } - - /* The function prototype is designed to maintain the expected Berkeley - sockets standard, but this implementation does not use all the parameters. */ - ( void ) uxAddressLength; - - configASSERT( pxSocket ); - configASSERT( pxSocket != FREERTOS_INVALID_SOCKET ); - - #if( ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 ) - { - /* pxAddress will be NULL if sendto() was called on a socket without the - socket being bound to an address. In this case, automatically allocate - an address and port to the socket. */ - if( pxAddress == NULL ) - { - pxAddress = &xAddress; - /* Put the port to zero to be assigned later. */ - pxAddress->sin_port = 0u; - } - } - #endif /* ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 */ - - /* Sockets must be bound before calling FreeRTOS_sendto() if - ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is not set to 1. */ - configASSERT( pxAddress ); - - if( pxAddress != NULL ) - { - if( pxAddress->sin_port == 0u ) - { - pxAddress->sin_port = prvGetPrivatePortNumber( ( BaseType_t )pxSocket->ucProtocol ); - if( 0 == pxAddress->sin_port ) - { - return -pdFREERTOS_ERRNO_EADDRNOTAVAIL; - } - } - - /* If vSocketBind() is called from the API FreeRTOS_bind() it has been - confirmed that the socket was not yet bound to a port. If it is called - from the IP-task, no such check is necessary. */ - - /* Check to ensure the port is not already in use. If the bind is - called internally, a port MAY be used by more than one socket. */ - if( ( ( xInternal == pdFALSE ) || ( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) ) && - ( pxListFindListItemWithValue( pxSocketList, ( TickType_t ) pxAddress->sin_port ) != NULL ) ) - { - FreeRTOS_debug_printf( ( "vSocketBind: %sP port %d in use\n", - pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP ? "TC" : "UD", - FreeRTOS_ntohs( pxAddress->sin_port ) ) ); - xReturn = -pdFREERTOS_ERRNO_EADDRINUSE; - } - else - { - /* Allocate the port number to the socket. - This macro will set 'xBoundSocketListItem->xItemValue' */ - socketSET_SOCKET_PORT( pxSocket, pxAddress->sin_port ); - - /* And also store it in a socket field 'usLocalPort' in host-byte-order, - mostly used for logging and debugging purposes */ - pxSocket->usLocalPort = FreeRTOS_ntohs( pxAddress->sin_port ); - - /* Add the socket to the list of bound ports. */ - { - /* If the network driver can iterate through 'xBoundUDPSocketsList', - by calling xPortHasUDPSocket() then the IP-task must temporarily - suspend the scheduler to keep the list in a consistent state. */ - #if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 ) - { - vTaskSuspendAll(); - } - #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */ - - /* Add the socket to 'xBoundUDPSocketsList' or 'xBoundTCPSocketsList' */ - vListInsertEnd( pxSocketList, &( pxSocket->xBoundSocketListItem ) ); - - #if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 ) - { - xTaskResumeAll(); - } - #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */ - } - } - } - else - { - xReturn = -pdFREERTOS_ERRNO_EADDRNOTAVAIL; - FreeRTOS_debug_printf( ( "vSocketBind: Socket no addr\n" ) ); - } - - if( xReturn != 0 ) - { - iptraceBIND_FAILED( xSocket, ( FreeRTOS_ntohs( pxAddress->sin_port ) ) ); - } - - return xReturn; -} /* Tested */ -/*-----------------------------------------------------------*/ - -/* - * Close a socket and free the allocated space - * In case of a TCP socket: the connection will not be closed automatically - * Subsequent messages for the closed socket will be responded to with a RST - * The IP-task will actually close the socket, after receiving a 'eSocketCloseEvent' message - */ -BaseType_t FreeRTOS_closesocket( Socket_t xSocket ) -{ -BaseType_t xResult; -#if( ipconfigUSE_TCP == 1 ) && ( ipconfigUSE_CALLBACKS == 1 ) - FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * )xSocket; -#endif -IPStackEvent_t xCloseEvent; -xCloseEvent.eEventType = eSocketCloseEvent; -xCloseEvent.pvData = ( void * ) xSocket; - - if( ( xSocket == NULL ) || ( xSocket == FREERTOS_INVALID_SOCKET ) ) - { - xResult = 0; - } - else - { - #if( ( ipconfigUSE_TCP == 1 ) && ( ipconfigUSE_CALLBACKS == 1 ) ) - { - if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP ) - { - /* Make sure that IP-task won't call the user callback's anymore */ - pxSocket->u.xTCP.pxHandleConnected = NULL; - pxSocket->u.xTCP.pxHandleReceive = NULL; - pxSocket->u.xTCP.pxHandleSent = NULL; - } - } - #endif /* ( ( ipconfigUSE_TCP == 1 ) && ( ipconfigUSE_CALLBACKS == 1 ) ) */ - - /* Let the IP task close the socket to keep it synchronised with the - packet handling. */ - - /* Note when changing the time-out value below, it must be checked who is calling - this function. If it is called by the IP-task, a deadlock could occur. - The IP-task would only call it in case of a user call-back */ - if( xSendEventStructToIPTask( &xCloseEvent, ( TickType_t ) 0 ) == pdFAIL ) - { - FreeRTOS_debug_printf( ( "FreeRTOS_closesocket: failed\n" ) ); - xResult = -1; - } - else - { - xResult = 1; - } - } - - return xResult; -} - -/* This is the internal version of FreeRTOS_closesocket() - * It will be called by the IPtask only to avoid problems with synchronicity - */ -void *vSocketClose( FreeRTOS_Socket_t *pxSocket ) -{ -NetworkBufferDescriptor_t *pxNetworkBuffer; - - #if( ipconfigUSE_TCP == 1 ) - { - /* For TCP: clean up a little more. */ - if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP ) - { - #if( ipconfigUSE_TCP_WIN == 1 ) - { - if( pxSocket->u.xTCP.pxAckMessage != NULL ) - { - vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage ); - } - /* Free the resources which were claimed by the tcpWin member */ - vTCPWindowDestroy( &pxSocket->u.xTCP.xTCPWindow ); - } - #endif /* ipconfigUSE_TCP_WIN */ - - /* Free the input and output streams */ - if( pxSocket->u.xTCP.rxStream != NULL ) - { - vPortFreeLarge( pxSocket->u.xTCP.rxStream ); - } - - if( pxSocket->u.xTCP.txStream != NULL ) - { - vPortFreeLarge( pxSocket->u.xTCP.txStream ); - } - - /* In case this is a child socket, make sure the child-count of the - parent socket is decreased. */ - prvTCPSetSocketCount( pxSocket ); - } - } - #endif /* ipconfigUSE_TCP == 1 */ - - /* Socket must be unbound first, to ensure no more packets are queued on - it. */ - if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE ) - { - /* If the network driver can iterate through 'xBoundUDPSocketsList', - by calling xPortHasUDPSocket(), then the IP-task must temporarily - suspend the scheduler to keep the list in a consistent state. */ - #if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 ) - { - vTaskSuspendAll(); - } - #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */ - - uxListRemove( &( pxSocket->xBoundSocketListItem ) ); - - #if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 ) - { - xTaskResumeAll(); - } - #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */ - } - - /* Now the socket is not bound the list of waiting packets can be - drained. */ - if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_UDP ) - { - while( listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ) > 0U ) - { - pxNetworkBuffer = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->u.xUDP.xWaitingPacketsList ) ); - uxListRemove( &( pxNetworkBuffer->xBufferListItem ) ); - vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); - } - } - - if( pxSocket->xEventGroup ) - { - vEventGroupDelete( pxSocket->xEventGroup ); - } - - #if( ipconfigUSE_TCP == 1 ) && ( ipconfigHAS_DEBUG_PRINTF != 0 ) - { - if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP ) - { - FreeRTOS_debug_printf( ( "FreeRTOS_closesocket[%u to %lxip:%u]: buffers %lu socks %lu\n", - pxSocket->usLocalPort, - pxSocket->u.xTCP.ulRemoteIP, - pxSocket->u.xTCP.usRemotePort, - uxGetNumberOfFreeNetworkBuffers(), - listCURRENT_LIST_LENGTH( &xBoundTCPSocketsList ) ) ); - } - } - #endif /* ( ipconfigUSE_TCP == 1 ) && ( ipconfigHAS_DEBUG_PRINTF != 0 ) */ - - /* Anf finally, after all resources have been freed, free the socket space */ - vPortFreeSocket( pxSocket ); - - return 0; -} /* Tested */ - -/*-----------------------------------------------------------*/ - -#if ipconfigUSE_TCP == 1 - - /* - * When a child socket gets closed, make sure to update the child-count of the - * parent. When a listening parent socket is closed, make sure no child-sockets - * keep a pointer to it. - */ - static void prvTCPSetSocketCount( FreeRTOS_Socket_t *pxSocketToDelete ) - { - const ListItem_t *pxIterator; - const MiniListItem_t *pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( &xBoundTCPSocketsList ); - FreeRTOS_Socket_t *pxOtherSocket; - uint16_t usLocalPort = pxSocketToDelete->usLocalPort; - - for( pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd ); - pxIterator != ( const ListItem_t * ) pxEnd; - pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) ) - { - pxOtherSocket = ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator ); - if( ( pxOtherSocket->u.xTCP.ucTCPState == eTCP_LISTEN ) && - ( pxOtherSocket->usLocalPort == usLocalPort ) && - ( pxOtherSocket->u.xTCP.usChildCount ) ) - { - pxOtherSocket->u.xTCP.usChildCount--; - FreeRTOS_debug_printf( ( "Lost: Socket %u now has %u / %u child%s\n", - pxOtherSocket->usLocalPort, - pxOtherSocket->u.xTCP.usChildCount, - pxOtherSocket->u.xTCP.usBacklog, - pxOtherSocket->u.xTCP.usChildCount == 1u ? "" : "ren" ) ); - break; - } - } - } - -#endif /* ipconfigUSE_TCP == 1 */ - -/*-----------------------------------------------------------*/ - -BaseType_t FreeRTOS_setsockopt( Socket_t xSocket, int32_t lLevel, int32_t lOptionName, const void *pvOptionValue, size_t xOptionLength ) -{ -/* The standard Berkeley function returns 0 for success. */ -BaseType_t xReturn = -pdFREERTOS_ERRNO_EINVAL; -BaseType_t lOptionValue; -FreeRTOS_Socket_t *pxSocket; - - pxSocket = ( FreeRTOS_Socket_t * ) xSocket; - - /* The function prototype is designed to maintain the expected Berkeley - sockets standard, but this implementation does not use all the parameters. */ - ( void ) lLevel; - ( void ) xOptionLength; - - configASSERT( xSocket ); - - switch( lOptionName ) - { - case FREERTOS_SO_RCVTIMEO : - /* Receive time out. */ - pxSocket->xReceiveBlockTime = *( ( TickType_t * ) pvOptionValue ); - xReturn = 0; - break; - - case FREERTOS_SO_SNDTIMEO : - pxSocket->xSendBlockTime = *( ( TickType_t * ) pvOptionValue ); - if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_UDP ) - { - /* The send time out is capped for the reason stated in the - comments where ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS is defined - in FreeRTOSIPConfig.h (assuming an official configuration file - is being used. */ - if( pxSocket->xSendBlockTime > ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS ) - { - pxSocket->xSendBlockTime = ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS; - } - } - else - { - /* For TCP socket, it isn't necessary to limit the blocking time - because the FreeRTOS_send() function does not wait for a network - buffer to become available. */ - } - xReturn = 0; - break; - #if( ipconfigUDP_MAX_RX_PACKETS > 0 ) - case FREERTOS_SO_UDP_MAX_RX_PACKETS: - if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_UDP ) - { - break; /* will return -pdFREERTOS_ERRNO_EINVAL */ - } - pxSocket->u.xUDP.uxMaxPackets = *( ( UBaseType_t * ) pvOptionValue ); - xReturn = 0; - break; - #endif /* ipconfigUDP_MAX_RX_PACKETS */ - - case FREERTOS_SO_UDPCKSUM_OUT : - /* Turn calculating of the UDP checksum on/off for this socket. */ - lOptionValue = ( BaseType_t ) pvOptionValue; - - if( lOptionValue == 0 ) - { - pxSocket->ucSocketOptions &= ( uint8_t ) ~FREERTOS_SO_UDPCKSUM_OUT; - } - else - { - pxSocket->ucSocketOptions |= ( uint8_t ) FREERTOS_SO_UDPCKSUM_OUT; - } - xReturn = 0; - break; - - #if( ipconfigUSE_CALLBACKS == 1 ) - #if( ipconfigUSE_TCP == 1 ) - case FREERTOS_SO_TCP_CONN_HANDLER: /* Set a callback for (dis)connection events */ - case FREERTOS_SO_TCP_RECV_HANDLER: /* Install a callback for receiving TCP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */ - case FREERTOS_SO_TCP_SENT_HANDLER: /* Install a callback for sending TCP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */ - #endif /* ipconfigUSE_TCP */ - case FREERTOS_SO_UDP_RECV_HANDLER: /* Install a callback for receiving UDP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */ - case FREERTOS_SO_UDP_SENT_HANDLER: /* Install a callback for sending UDP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */ - { - #if( ipconfigUSE_TCP == 1 ) - { - UBaseType_t uxProtocol; - if( ( lOptionName == FREERTOS_SO_UDP_RECV_HANDLER ) || - ( lOptionName == FREERTOS_SO_UDP_SENT_HANDLER ) ) - { - uxProtocol = ( UBaseType_t ) FREERTOS_IPPROTO_UDP; - } - else - { - uxProtocol = ( UBaseType_t ) FREERTOS_IPPROTO_TCP; - } - - if( pxSocket->ucProtocol != ( uint8_t ) uxProtocol ) - { - break; /* will return -pdFREERTOS_ERRNO_EINVAL */ - } - } - #else - { - /* No need to check if the socket has the right - protocol, because only UDP socket can be created. */ - } - #endif /* ipconfigUSE_TCP */ - - switch( lOptionName ) - { - #if ipconfigUSE_TCP == 1 - case FREERTOS_SO_TCP_CONN_HANDLER: - pxSocket->u.xTCP.pxHandleConnected = ((F_TCP_UDP_Handler_t *)pvOptionValue)->pxOnTCPConnected; - break; - case FREERTOS_SO_TCP_RECV_HANDLER: - pxSocket->u.xTCP.pxHandleReceive = ((F_TCP_UDP_Handler_t *)pvOptionValue)->pxOnTCPReceive; - break; - case FREERTOS_SO_TCP_SENT_HANDLER: - pxSocket->u.xTCP.pxHandleSent = ((F_TCP_UDP_Handler_t *)pvOptionValue)->pxOnTCPSent; - break; - #endif /* ipconfigUSE_TCP */ - case FREERTOS_SO_UDP_RECV_HANDLER: - pxSocket->u.xUDP.pxHandleReceive = ((F_TCP_UDP_Handler_t *)pvOptionValue)->pxOnUDPReceive; - break; - case FREERTOS_SO_UDP_SENT_HANDLER: - pxSocket->u.xUDP.pxHandleSent = ((F_TCP_UDP_Handler_t *)pvOptionValue)->pxOnUDPSent; - break; - default: - break; - } - } - - xReturn = 0; - break; - #endif /* ipconfigUSE_CALLBACKS */ - - #if( ipconfigUSE_TCP != 0 ) - #if( ipconfigSOCKET_HAS_USER_SEMAPHORE != 0 ) - /* Each socket has a semaphore on which the using task normally - sleeps. */ - case FREERTOS_SO_SET_SEMAPHORE: - { - pxSocket->pxUserSemaphore = *( ( SemaphoreHandle_t * ) pvOptionValue ); - xReturn = 0; - } - break; - #endif /* ipconfigSOCKET_HAS_USER_SEMAPHORE */ - - #if( ipconfigSOCKET_HAS_USER_WAKE_CALLBACK != 0 ) - case FREERTOS_SO_WAKEUP_CALLBACK: - { - /* Each socket can have a callback function that is executed - when there is an event the socket's owner might want to - process. */ - pxSocket->pxUserWakeCallback = ( SocketWakeupCallback_t ) pvOptionValue; - xReturn = 0; - } - break; - #endif /* ipconfigSOCKET_HAS_USER_WAKE_CALLBACK */ - - case FREERTOS_SO_SET_LOW_HIGH_WATER: - { - LowHighWater_t *pxLowHighWater = ( LowHighWater_t * ) pvOptionValue; - - if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) - { - /* It is not allowed to access 'pxSocket->u.xTCP'. */ - FreeRTOS_debug_printf( ( "FREERTOS_SO_SET_LOW_HIGH_WATER: wrong socket type\n" ) ); - break; /* will return -pdFREERTOS_ERRNO_EINVAL */ - } - if( ( pxLowHighWater->uxLittleSpace >= pxLowHighWater->uxEnoughSpace ) || - ( pxLowHighWater->uxEnoughSpace > pxSocket->u.xTCP.uxRxStreamSize ) ) - { - /* Impossible values. */ - FreeRTOS_debug_printf( ( "FREERTOS_SO_SET_LOW_HIGH_WATER: bad values\n" ) ); - break; /* will return -pdFREERTOS_ERRNO_EINVAL */ - } - /* Send a STOP when buffer space drops below 'uxLittleSpace' bytes. */ - pxSocket->u.xTCP.uxLittleSpace = pxLowHighWater->uxLittleSpace; - /* Send a GO when buffer space grows above 'uxEnoughSpace' bytes. */ - pxSocket->u.xTCP.uxEnoughSpace = pxLowHighWater->uxEnoughSpace; - xReturn = 0; - } - break; - - case FREERTOS_SO_SNDBUF: /* Set the size of the send buffer, in units of MSS (TCP only) */ - case FREERTOS_SO_RCVBUF: /* Set the size of the receive buffer, in units of MSS (TCP only) */ - { - uint32_t ulNewValue; - - if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) - { - FreeRTOS_debug_printf( ( "Set SO_%sBUF: wrong socket type\n", - ( lOptionName == FREERTOS_SO_SNDBUF ) ? "SND" : "RCV" ) ); - break; /* will return -pdFREERTOS_ERRNO_EINVAL */ - } - - if( ( ( lOptionName == FREERTOS_SO_SNDBUF ) && ( pxSocket->u.xTCP.txStream != NULL ) ) || - ( ( lOptionName == FREERTOS_SO_RCVBUF ) && ( pxSocket->u.xTCP.rxStream != NULL ) ) ) - { - FreeRTOS_debug_printf( ( "Set SO_%sBUF: buffer already created\n", - ( lOptionName == FREERTOS_SO_SNDBUF ) ? "SND" : "RCV" ) ); - break; /* will return -pdFREERTOS_ERRNO_EINVAL */ - } - - ulNewValue = *( ( uint32_t * ) pvOptionValue ); - - if( lOptionName == FREERTOS_SO_SNDBUF ) - { - /* Round up to nearest MSS size */ - ulNewValue = FreeRTOS_round_up( ulNewValue, ( uint32_t ) pxSocket->u.xTCP.usInitMSS ); - pxSocket->u.xTCP.uxTxStreamSize = ulNewValue; - } - else - { - pxSocket->u.xTCP.uxRxStreamSize = ulNewValue; - } - } - xReturn = 0; - break; - - case FREERTOS_SO_WIN_PROPERTIES: /* Set all buffer and window properties in one call, parameter is pointer to WinProperties_t */ - { - WinProperties_t* pxProps; - - if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) - { - FreeRTOS_debug_printf( ( "Set SO_WIN_PROP: wrong socket type\n" ) ); - break; /* will return -pdFREERTOS_ERRNO_EINVAL */ - } - - if( ( pxSocket->u.xTCP.txStream != NULL ) || ( pxSocket->u.xTCP.rxStream != NULL ) ) - { - FreeRTOS_debug_printf( ( "Set SO_WIN_PROP: buffer already created\n" ) ); - break; /* will return -pdFREERTOS_ERRNO_EINVAL */ - } - - pxProps = ( ( WinProperties_t * ) pvOptionValue ); - - if ( FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDBUF, &( pxProps->lTxBufSize ), sizeof( pxProps->lTxBufSize ) ) != 0 ) - { - break; /* will return -pdFREERTOS_ERRNO_EINVAL */ - } - - if ( FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVBUF, &( pxProps->lRxBufSize ), sizeof( pxProps->lRxBufSize ) ) != 0 ) - { - break; /* will return -pdFREERTOS_ERRNO_EINVAL */ - } - - #if( ipconfigUSE_TCP_WIN == 1 ) - { - pxSocket->u.xTCP.uxRxWinSize = ( uint32_t )pxProps->lRxWinSize; /* Fixed value: size of the TCP reception window */ - pxSocket->u.xTCP.uxTxWinSize = ( uint32_t )pxProps->lTxWinSize; /* Fixed value: size of the TCP transmit window */ - } - #else - { - pxSocket->u.xTCP.uxRxWinSize = 1u; - pxSocket->u.xTCP.uxTxWinSize = 1u; - } - #endif - - /* In case the socket has already initialised its tcpWin, - adapt the window size parameters */ - if( pxSocket->u.xTCP.xTCPWindow.u.bits.bHasInit != pdFALSE_UNSIGNED ) - { - pxSocket->u.xTCP.xTCPWindow.xSize.ulRxWindowLength = pxSocket->u.xTCP.uxRxWinSize * pxSocket->u.xTCP.usInitMSS; - pxSocket->u.xTCP.xTCPWindow.xSize.ulTxWindowLength = pxSocket->u.xTCP.uxTxWinSize * pxSocket->u.xTCP.usInitMSS; - } - } - - xReturn = 0; - break; - - case FREERTOS_SO_REUSE_LISTEN_SOCKET: /* If true, the server-socket will turn into a connected socket */ - { - if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) - { - break; /* will return -pdFREERTOS_ERRNO_EINVAL */ - } - if( *( ( BaseType_t * ) pvOptionValue ) != 0 ) - { - pxSocket->u.xTCP.bits.bReuseSocket = pdTRUE_UNSIGNED; - } - else - { - pxSocket->u.xTCP.bits.bReuseSocket = pdFALSE_UNSIGNED; - } - } - xReturn = 0; - break; - - case FREERTOS_SO_CLOSE_AFTER_SEND: /* As soon as the last byte has been transmitted, finalise the connection */ - { - if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) - { - break; /* will return -pdFREERTOS_ERRNO_EINVAL */ - } - - if( *( ( BaseType_t * ) pvOptionValue ) != 0 ) - { - pxSocket->u.xTCP.bits.bCloseAfterSend = pdTRUE_UNSIGNED; - } - else - { - pxSocket->u.xTCP.bits.bCloseAfterSend = pdFALSE_UNSIGNED; - } - } - xReturn = 0; - break; - - case FREERTOS_SO_SET_FULL_SIZE: /* Refuse to send packets smaller than MSS */ - { - if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) - { - break; /* will return -pdFREERTOS_ERRNO_EINVAL */ - } - - if( *( ( BaseType_t * ) pvOptionValue ) != 0 ) - { - pxSocket->u.xTCP.xTCPWindow.u.bits.bSendFullSize = pdTRUE_UNSIGNED; - } - else - { - pxSocket->u.xTCP.xTCPWindow.u.bits.bSendFullSize = pdFALSE_UNSIGNED; - } - - if( ( pxSocket->u.xTCP.xTCPWindow.u.bits.bSendFullSize == pdFALSE_UNSIGNED ) && - ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) && - ( FreeRTOS_outstanding( pxSocket ) != 0 ) ) - { - pxSocket->u.xTCP.usTimeout = 1u; /* to set/clear bSendFullSize */ - xSendEventToIPTask( eTCPTimerEvent ); - } - } - xReturn = 0; - break; - - case FREERTOS_SO_STOP_RX: /* Refuse to receive more packts */ - { - if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) - { - break; /* will return -pdFREERTOS_ERRNO_EINVAL */ - } - - if( *( ( BaseType_t * ) pvOptionValue ) != 0 ) - { - pxSocket->u.xTCP.bits.bRxStopped = pdTRUE_UNSIGNED; - } - else - { - pxSocket->u.xTCP.bits.bRxStopped = pdFALSE_UNSIGNED; - } - - pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED; - pxSocket->u.xTCP.usTimeout = 1u; /* to set/clear bRxStopped */ - xSendEventToIPTask( eTCPTimerEvent ); - } - xReturn = 0; - break; - - #endif /* ipconfigUSE_TCP == 1 */ - - default : - /* No other options are handled. */ - xReturn = -pdFREERTOS_ERRNO_ENOPROTOOPT; - break; - } - - return xReturn; -} /* Tested */ - -/*-----------------------------------------------------------*/ - -/* Find an available port number per https://tools.ietf.org/html/rfc6056. */ -static uint16_t prvGetPrivatePortNumber( BaseType_t xProtocol ) -{ -const uint16_t usEphemeralPortCount = - socketAUTO_PORT_ALLOCATION_MAX_NUMBER - socketAUTO_PORT_ALLOCATION_START_NUMBER + 1; -uint16_t usIterations = usEphemeralPortCount; -uint32_t ulRandomSeed = 0; -uint16_t usResult = 0; -const List_t *pxList; - -#if ipconfigUSE_TCP == 1 - if( xProtocol == ( BaseType_t ) FREERTOS_IPPROTO_TCP ) - { - pxList = &xBoundTCPSocketsList; - } - else -#endif - { - pxList = &xBoundUDPSocketsList; - } - - /* Avoid compiler warnings if ipconfigUSE_TCP is not defined. */ - ( void ) xProtocol; - - /* Find the next available port using the random seed as a starting - point. */ - do - { - /* Only proceed if the random number generator succeeded. */ - if( xApplicationGetRandomNumber( &( ulRandomSeed ) ) == pdFALSE ) - { - break; - } - - /* Map the random to a candidate port. */ - usResult = - socketAUTO_PORT_ALLOCATION_START_NUMBER + - ( ( ( uint16_t )ulRandomSeed ) % usEphemeralPortCount ); - - /* Check if there's already an open socket with the same protocol - and port. */ - if( NULL == pxListFindListItemWithValue( - pxList, - ( TickType_t )FreeRTOS_htons( usResult ) ) ) - { - usResult = FreeRTOS_htons( usResult ); - break; - } - else - { - usResult = 0; - } - - usIterations--; - } - while( usIterations > 0 ); - - return usResult; -} -/*-----------------------------------------------------------*/ - -/* pxListFindListItemWithValue: find a list item in a bound socket list -'xWantedItemValue' refers to a port number */ -static const ListItem_t * pxListFindListItemWithValue( const List_t *pxList, TickType_t xWantedItemValue ) -{ -const ListItem_t * pxResult = NULL; - - if( ( xIPIsNetworkTaskReady() != pdFALSE ) && ( pxList != NULL ) ) - { - const ListItem_t *pxIterator; - const MiniListItem_t *pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( pxList ); - for( pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd ); - pxIterator != ( const ListItem_t * ) pxEnd; - pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) ) - { - if( listGET_LIST_ITEM_VALUE( pxIterator ) == xWantedItemValue ) - { - pxResult = pxIterator; - break; - } - } - } - - return pxResult; -} /* Tested */ - -/*-----------------------------------------------------------*/ - -FreeRTOS_Socket_t *pxUDPSocketLookup( UBaseType_t uxLocalPort ) -{ -const ListItem_t *pxListItem; -FreeRTOS_Socket_t *pxSocket = NULL; - - /* Looking up a socket is quite simple, find a match with the local port. - - See if there is a list item associated with the port number on the - list of bound sockets. */ - pxListItem = pxListFindListItemWithValue( &xBoundUDPSocketsList, ( TickType_t ) uxLocalPort ); - - if( pxListItem != NULL ) - { - /* The owner of the list item is the socket itself. */ - pxSocket = ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxListItem ); - configASSERT( pxSocket != NULL ); - } - return pxSocket; -} - -/*-----------------------------------------------------------*/ - -#if ipconfigINCLUDE_FULL_INET_ADDR == 1 - - uint32_t FreeRTOS_inet_addr( const char * pcIPAddress ) - { - const uint32_t ulDecimalBase = 10u; - uint8_t ucOctet[ socketMAX_IP_ADDRESS_OCTETS ]; - const char *pcPointerOnEntering; - uint32_t ulReturn = 0UL, ulValue; - UBaseType_t uxOctetNumber; - BaseType_t xResult = pdPASS; - - for( uxOctetNumber = 0u; uxOctetNumber < socketMAX_IP_ADDRESS_OCTETS; uxOctetNumber++ ) - { - ulValue = 0ul; - pcPointerOnEntering = pcIPAddress; - - while( ( *pcIPAddress >= '0' ) && ( *pcIPAddress <= '9' ) ) - { - /* Move previous read characters into the next decimal - position. */ - ulValue *= ulDecimalBase; - - /* Add the binary value of the ascii character. */ - ulValue += ( ( uint32_t ) ( *pcIPAddress ) - ( uint32_t ) '0' ); - - /* Move to next character in the string. */ - pcIPAddress++; - } - - /* Check characters were read. */ - if( pcIPAddress == pcPointerOnEntering ) - { - xResult = pdFAIL; - } - - /* Check the value fits in an 8-bit number. */ - if( ulValue > 0xffUL ) - { - xResult = pdFAIL; - } - else - { - ucOctet[ uxOctetNumber ] = ( uint8_t ) ulValue; - - /* Check the next character is as expected. */ - if( uxOctetNumber < ( socketMAX_IP_ADDRESS_OCTETS - 1u ) ) - { - if( *pcIPAddress != '.' ) - { - xResult = pdFAIL; - } - else - { - /* Move past the dot. */ - pcIPAddress++; - } - } - } - - if( xResult == pdFAIL ) - { - /* No point going on. */ - break; - } - } - - if( *pcIPAddress != ( char ) 0 ) - { - /* Expected the end of the string. */ - xResult = pdFAIL; - } - - if( uxOctetNumber != socketMAX_IP_ADDRESS_OCTETS ) - { - /* Didn't read enough octets. */ - xResult = pdFAIL; - } - - if( xResult == pdPASS ) - { - ulReturn = FreeRTOS_inet_addr_quick( ucOctet[ 0 ], ucOctet[ 1 ], ucOctet[ 2 ], ucOctet[ 3 ] ); - } - - return ulReturn; - } - -#endif /* ipconfigINCLUDE_FULL_INET_ADDR */ - -/*-----------------------------------------------------------*/ - -/* Function to get the local address and IP port */ -size_t FreeRTOS_GetLocalAddress( Socket_t xSocket, struct freertos_sockaddr *pxAddress ) -{ -FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; - - /* IP address of local machine. */ - pxAddress->sin_addr = *ipLOCAL_IP_ADDRESS_POINTER; - - /* Local port on this machine. */ - pxAddress->sin_port = FreeRTOS_htons( pxSocket->usLocalPort ); - - return sizeof( *pxAddress ); -} - -/*-----------------------------------------------------------*/ - -void vSocketWakeUpUser( FreeRTOS_Socket_t *pxSocket ) -{ -/* _HT_ must work this out, now vSocketWakeUpUser will be called for any important - * event or transition */ - #if( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 ) - { - if( pxSocket->pxUserSemaphore != NULL ) - { - xSemaphoreGive( pxSocket->pxUserSemaphore ); - } - } - #endif /* ipconfigSOCKET_HAS_USER_SEMAPHORE */ - - #if( ipconfigSOCKET_HAS_USER_WAKE_CALLBACK == 1 ) - { - if( pxSocket->pxUserWakeCallback != NULL ) - { - pxSocket->pxUserWakeCallback( pxSocket ); - } - } - #endif /* ipconfigSOCKET_HAS_USER_SEMAPHORE */ - - #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) - { - if( pxSocket->pxSocketSet != NULL ) - { - EventBits_t xSelectBits = ( pxSocket->xEventBits >> SOCKET_EVENT_BIT_COUNT ) & eSELECT_ALL; - if( xSelectBits != 0ul ) - { - pxSocket->xSocketBits |= xSelectBits; - xEventGroupSetBits( pxSocket->pxSocketSet->xSelectGroup, xSelectBits ); - } - } - - pxSocket->xEventBits &= eSOCKET_ALL; - } - #endif /* ipconfigSUPPORT_SELECT_FUNCTION */ - - if( ( pxSocket->xEventGroup != NULL ) && ( pxSocket->xEventBits != 0u ) ) - { - xEventGroupSetBits( pxSocket->xEventGroup, pxSocket->xEventBits ); - } - - pxSocket->xEventBits = 0ul; -} - -/*-----------------------------------------------------------*/ - -#if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 ) - - /* This define makes it possible for network-card drivers to inspect - * UDP message and see if there is any UDP socket bound to a given port - * number. - * This is probably only usefull in systems with a minimum of RAM and - * when lots of anonymous broadcast messages come in - */ - BaseType_t xPortHasUDPSocket( uint16_t usPortNr ) - { - BaseType_t xFound = pdFALSE; - - vTaskSuspendAll(); - { - if( ( pxListFindListItemWithValue( &xBoundUDPSocketsList, ( TickType_t ) usPortNr ) != NULL ) ) - { - xFound = pdTRUE; - } - } - xTaskResumeAll(); - - return xFound; - } - -#endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */ - -/*-----------------------------------------------------------*/ - -#if( ipconfigUSE_TCP == 1 ) - - static BaseType_t bMayConnect( FreeRTOS_Socket_t *pxSocket ); - static BaseType_t bMayConnect( FreeRTOS_Socket_t *pxSocket ) - { - switch( pxSocket->u.xTCP.ucTCPState ) - { - case eCLOSED: - case eCLOSE_WAIT: return 0; - case eCONNECT_SYN: return -pdFREERTOS_ERRNO_EINPROGRESS; - default: return -pdFREERTOS_ERRNO_EAGAIN; - } - } - -#endif /* ipconfigUSE_TCP */ -/*-----------------------------------------------------------*/ - -#if( ipconfigUSE_TCP == 1 ) - - static BaseType_t prvTCPConnectStart( FreeRTOS_Socket_t *pxSocket, struct freertos_sockaddr *pxAddress ) - { - BaseType_t xResult = 0; - - if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdFALSE ) == pdFALSE ) - { - /* Not a valid socket or wrong type */ - xResult = -pdFREERTOS_ERRNO_EBADF; - } - else if( FreeRTOS_issocketconnected( pxSocket ) > 0 ) - { - /* The socket is already connected. */ - xResult = -pdFREERTOS_ERRNO_EISCONN; - } - else if( socketSOCKET_IS_BOUND( pxSocket ) == pdFALSE ) - { - /* Bind the socket to the port that the client task will send from. - Non-standard, so the error returned is that returned by bind(). */ - xResult = FreeRTOS_bind( ( Socket_t ) pxSocket, NULL, 0u ); - } - - if( xResult == 0 ) - { - /* Check if it makes any sense to wait for a connect event, this condition - might change while sleeping, so it must be checked within each loop */ - xResult = bMayConnect( pxSocket ); /* -EINPROGRESS, -EAGAIN, or 0 for OK */ - - /* Start the connect procedure, kernel will start working on it */ - if( xResult == 0 ) - { - pxSocket->u.xTCP.bits.bConnPrepared = pdFALSE_UNSIGNED; - pxSocket->u.xTCP.ucRepCount = 0u; - - FreeRTOS_debug_printf( ( "FreeRTOS_connect: %u to %lxip:%u\n", - pxSocket->usLocalPort, FreeRTOS_ntohl( pxAddress->sin_addr ), FreeRTOS_ntohs( pxAddress->sin_port ) ) ); - - /* Port on remote machine. */ - pxSocket->u.xTCP.usRemotePort = FreeRTOS_ntohs( pxAddress->sin_port ); - - /* IP address of remote machine. */ - pxSocket->u.xTCP.ulRemoteIP = FreeRTOS_ntohl( pxAddress->sin_addr ); - - /* (client) internal state: socket wants to send a connect. */ - vTCPStateChange( pxSocket, eCONNECT_SYN ); - - /* To start an active connect. */ - pxSocket->u.xTCP.usTimeout = 1u; - - if( xSendEventToIPTask( eTCPTimerEvent ) != pdPASS ) - { - xResult = -pdFREERTOS_ERRNO_ECANCELED; - } - } - } - - return xResult; - } - -#endif /* ipconfigUSE_TCP */ -/*-----------------------------------------------------------*/ - -#if( ipconfigUSE_TCP == 1 ) - - /* - * FreeRTOS_connect: socket wants to connect to a remote port - */ - BaseType_t FreeRTOS_connect( Socket_t xClientSocket, struct freertos_sockaddr *pxAddress, socklen_t xAddressLength ) - { - FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t* ) xClientSocket; - TickType_t xRemainingTime; - BaseType_t xTimed = pdFALSE; - BaseType_t xResult; - TimeOut_t xTimeOut; - - ( void ) xAddressLength; - - xResult = prvTCPConnectStart( pxSocket, pxAddress ); - - if( xResult == 0 ) - { - /* And wait for the result */ - for( ;; ) - { - if( xTimed == pdFALSE ) - { - /* Only in the first round, check for non-blocking */ - xRemainingTime = pxSocket->xReceiveBlockTime; - if( xRemainingTime == ( TickType_t )0 ) - { - /* Not yet connected, correct state, non-blocking. */ - xResult = -pdFREERTOS_ERRNO_EWOULDBLOCK; - break; - } - - /* Don't get here a second time. */ - xTimed = pdTRUE; - - /* Fetch the current time */ - vTaskSetTimeOutState( &xTimeOut ); - } - - /* Did it get connected while sleeping ? */ - xResult = FreeRTOS_issocketconnected( pxSocket ); - - /* Returns positive when connected, negative means an error */ - if( xResult < 0 ) - { - /* Return the error */ - break; - } - - if( xResult > 0 ) - { - /* Socket now connected, return a zero */ - xResult = 0; - break; - } - - /* Is it allowed to sleep more? */ - if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) ) - { - xResult = -pdFREERTOS_ERRNO_ETIMEDOUT; - break; - } - - /* Go sleeping until we get any down-stream event */ - xEventGroupWaitBits( pxSocket->xEventGroup, eSOCKET_CONNECT, pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime ); - } - } - - return xResult; - } -#endif /* ipconfigUSE_TCP */ -/*-----------------------------------------------------------*/ - -#if( ipconfigUSE_TCP == 1 ) - - /* - * FreeRTOS_accept: can return a new connected socket - * if the server socket is in listen mode and receives a connection request - * The new socket will be bound already to the same port number as the listing - * socket. - */ - Socket_t FreeRTOS_accept( Socket_t xServerSocket, struct freertos_sockaddr *pxAddress, socklen_t *pxAddressLength ) - { - FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xServerSocket; - FreeRTOS_Socket_t *pxClientSocket = NULL; - TickType_t xRemainingTime; - BaseType_t xTimed = pdFALSE, xAsk = pdFALSE; - TimeOut_t xTimeOut; - IPStackEvent_t xAskEvent; - - if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE ) - { - /* Not a valid socket or wrong type */ - pxClientSocket = ( FreeRTOS_Socket_t * ) FREERTOS_INVALID_SOCKET; - } - else if( ( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED ) && - ( pxSocket->u.xTCP.ucTCPState != eTCP_LISTEN ) ) - { - /* Parent socket is not in listening mode */ - pxClientSocket = ( FreeRTOS_Socket_t * ) FREERTOS_INVALID_SOCKET; - } - else - { - /* Loop will stop with breaks. */ - for( ; ; ) - { - /* Is there a new client? */ - vTaskSuspendAll(); - { - if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED ) - { - pxClientSocket = pxSocket->u.xTCP.pxPeerSocket; - } - else - { - pxClientSocket = pxSocket; - } - if( pxClientSocket != NULL ) - { - pxSocket->u.xTCP.pxPeerSocket = NULL; - - /* Is it still not taken ? */ - if( pxClientSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) - { - pxClientSocket->u.xTCP.bits.bPassAccept = pdFALSE_UNSIGNED; - } - else - { - pxClientSocket = NULL; - } - } - } - xTaskResumeAll(); - - if( pxClientSocket != NULL ) - { - if( pxAddress != NULL ) - { - /* IP address of remote machine. */ - pxAddress->sin_addr = FreeRTOS_ntohl( pxClientSocket->u.xTCP.ulRemoteIP ); - - /* Port on remote machine. */ - pxAddress->sin_port = FreeRTOS_ntohs( pxClientSocket->u.xTCP.usRemotePort ); - } - if( pxAddressLength != NULL ) - { - *pxAddressLength = sizeof( *pxAddress ); - } - - if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED ) - { - xAsk = pdTRUE; - } - } - - if( xAsk != pdFALSE ) - { - /* Ask to set an event in 'xEventGroup' as soon as a new - client gets connected for this listening socket. */ - xAskEvent.eEventType = eTCPAcceptEvent; - xAskEvent.pvData = ( void * ) pxSocket; - xSendEventStructToIPTask( &xAskEvent, portMAX_DELAY ); - } - - if( pxClientSocket != NULL ) - { - break; - } - - if( xTimed == pdFALSE ) - { - /* Only in the first round, check for non-blocking */ - xRemainingTime = pxSocket->xReceiveBlockTime; - if( xRemainingTime == ( TickType_t ) 0 ) - { - break; - } - - /* Don't get here a second time */ - xTimed = pdTRUE; - - /* Fetch the current time */ - vTaskSetTimeOutState( &xTimeOut ); - } - - /* Has the timeout been reached? */ - if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE ) - { - break; - } - - /* Go sleeping until we get any down-stream event */ - xEventGroupWaitBits( pxSocket->xEventGroup, eSOCKET_ACCEPT, pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime ); - } - } - - return ( Socket_t ) pxClientSocket; - } -#endif /* ipconfigUSE_TCP */ -/*-----------------------------------------------------------*/ - -#if( ipconfigUSE_TCP == 1 ) - - /* - * Read incoming data from a TCP socket - * Only after the last byte has been read, a close error might be returned - */ - BaseType_t FreeRTOS_recv( Socket_t xSocket, void *pvBuffer, size_t xBufferLength, BaseType_t xFlags ) - { - BaseType_t xByteCount; - FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; - TickType_t xRemainingTime; - BaseType_t xTimed = pdFALSE; - TimeOut_t xTimeOut; - EventBits_t xEventBits = ( EventBits_t ) 0; - - /* Check if the socket is valid, has type TCP and if it is bound to a - port. */ - if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE ) - { - xByteCount = -pdFREERTOS_ERRNO_EINVAL; - } - else - { - if( pxSocket->u.xTCP.rxStream != NULL ) - { - xByteCount = ( BaseType_t )uxStreamBufferGetSize ( pxSocket->u.xTCP.rxStream ); - } - else - { - xByteCount = 0; - } - - while( xByteCount == 0 ) - { - switch( pxSocket->u.xTCP.ucTCPState ) - { - case eCLOSED: - case eCLOSE_WAIT: /* (server + client) waiting for a connection termination request from the local user. */ - case eCLOSING: /* (server + client) waiting for a connection termination request acknowledgement from the remote TCP. */ - if( pxSocket->u.xTCP.bits.bMallocError != pdFALSE_UNSIGNED ) - { - /* The no-memory error has priority above the non-connected error. - Both are fatal and will elad to closing the socket. */ - xByteCount = -pdFREERTOS_ERRNO_ENOMEM; - } - else - { - xByteCount = -pdFREERTOS_ERRNO_ENOTCONN; - } - /* Call continue to break out of the switch and also the while - loop. */ - continue; - default: - break; - } - - if( xTimed == pdFALSE ) - { - /* Only in the first round, check for non-blocking. */ - xRemainingTime = pxSocket->xReceiveBlockTime; - - if( xRemainingTime == ( TickType_t ) 0 ) - { - #if( ipconfigSUPPORT_SIGNALS != 0 ) - { - /* Just check for the interrupt flag. */ - xEventBits = xEventGroupWaitBits( pxSocket->xEventGroup, eSOCKET_INTR, - pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, socketDONT_BLOCK ); - } - #endif /* ipconfigSUPPORT_SIGNALS */ - break; - } - - if( ( xFlags & FREERTOS_MSG_DONTWAIT ) != 0 ) - { - break; - } - - /* Don't get here a second time. */ - xTimed = pdTRUE; - - /* Fetch the current time. */ - vTaskSetTimeOutState( &xTimeOut ); - } - - /* Has the timeout been reached? */ - if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE ) - { - break; - } - - /* Block until there is a down-stream event. */ - xEventBits = xEventGroupWaitBits( pxSocket->xEventGroup, - eSOCKET_RECEIVE | eSOCKET_CLOSED | eSOCKET_INTR, - pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime ); - #if( ipconfigSUPPORT_SIGNALS != 0 ) - { - if( ( xEventBits & eSOCKET_INTR ) != 0u ) - { - break; - } - } - #else - { - ( void ) xEventBits; - } - #endif /* ipconfigSUPPORT_SIGNALS */ - - if( pxSocket->u.xTCP.rxStream != NULL ) - { - xByteCount = ( BaseType_t ) uxStreamBufferGetSize ( pxSocket->u.xTCP.rxStream ); - } - else - { - xByteCount = 0; - } - } - - #if( ipconfigSUPPORT_SIGNALS != 0 ) - if( ( xEventBits & eSOCKET_INTR ) != 0 ) - { - if( ( xEventBits & ( eSOCKET_RECEIVE | eSOCKET_CLOSED ) ) != 0 ) - { - /* Shouldn't have cleared other flags. */ - xEventBits &= ~eSOCKET_INTR; - xEventGroupSetBits( pxSocket->xEventGroup, xEventBits ); - } - xByteCount = -pdFREERTOS_ERRNO_EINTR; - } - else - #endif /* ipconfigSUPPORT_SIGNALS */ - if( xByteCount > 0 ) - { - if( ( xFlags & FREERTOS_ZERO_COPY ) == 0 ) - { - xByteCount = ( BaseType_t ) uxStreamBufferGet( pxSocket->u.xTCP.rxStream, 0ul, ( uint8_t * ) pvBuffer, ( size_t ) xBufferLength, ( xFlags & FREERTOS_MSG_PEEK ) != 0 ); - if( pxSocket->u.xTCP.bits.bLowWater != pdFALSE_UNSIGNED ) - { - /* We had reached the low-water mark, now see if the flag - can be cleared */ - size_t uxFrontSpace = uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream ); - - if( uxFrontSpace >= pxSocket->u.xTCP.uxEnoughSpace ) - { - pxSocket->u.xTCP.bits.bLowWater = pdFALSE_UNSIGNED; - pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED; - pxSocket->u.xTCP.usTimeout = 1u; /* because bLowWater is cleared. */ - xSendEventToIPTask( eTCPTimerEvent ); - } - } - } - else - { - /* Zero-copy reception of data: pvBuffer is a pointer to a pointer. */ - xByteCount = ( BaseType_t ) uxStreamBufferGetPtr( pxSocket->u.xTCP.rxStream, (uint8_t **)pvBuffer ); - } - } - } /* prvValidSocket() */ - - return xByteCount; - } - -#endif /* ipconfigUSE_TCP */ -/*-----------------------------------------------------------*/ - -#if( ipconfigUSE_TCP == 1 ) - - static int32_t prvTCPSendCheck( FreeRTOS_Socket_t *pxSocket, size_t xDataLength ) - { - int32_t xResult = 1; - - /* Is this a socket of type TCP and is it already bound to a port number ? */ - if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE ) - { - xResult = -pdFREERTOS_ERRNO_EINVAL; - } - else if( pxSocket->u.xTCP.bits.bMallocError != pdFALSE_UNSIGNED ) - { - xResult = -pdFREERTOS_ERRNO_ENOMEM; - } - else if( pxSocket->u.xTCP.ucTCPState == eCLOSED || - pxSocket->u.xTCP.ucTCPState == eCLOSE_WAIT || - pxSocket->u.xTCP.ucTCPState == eCLOSING ) - { - xResult = -pdFREERTOS_ERRNO_ENOTCONN; - } - else if( pxSocket->u.xTCP.bits.bFinSent != pdFALSE_UNSIGNED ) - { - /* This TCP connection is closing already, the FIN flag has been sent. - Maybe it is still delivering or receiving data. - Return OK in order not to get closed/deleted too quickly */ - xResult = 0; - } - else if( xDataLength == 0ul ) - { - /* send() is being called to send zero bytes */ - xResult = 0; - } - else if( pxSocket->u.xTCP.txStream == NULL ) - { - /* Create the outgoing stream only when it is needed */ - prvTCPCreateStream( pxSocket, pdFALSE ); - - if( pxSocket->u.xTCP.txStream == NULL ) - { - xResult = -pdFREERTOS_ERRNO_ENOMEM; - } - } - - return xResult; - } - -#endif /* ipconfigUSE_TCP */ -/*-----------------------------------------------------------*/ - -#if( ipconfigUSE_TCP == 1 ) - - /* Get a direct pointer to the circular transmit buffer. - '*pxLength' will contain the number of bytes that may be written. */ - uint8_t *FreeRTOS_get_tx_head( Socket_t xSocket, BaseType_t *pxLength ) - { - uint8_t *pucReturn = NULL; - FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; - StreamBuffer_t *pxBuffer = NULL; - - *pxLength = 0; - - /* Confirm that this is a TCP socket before dereferencing structure - member pointers. */ - if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdFALSE ) == pdTRUE ) - { - pxBuffer = pxSocket->u.xTCP.txStream; - if( pxBuffer != NULL ) - { - BaseType_t xSpace = ( BaseType_t )uxStreamBufferGetSpace( pxBuffer ); - BaseType_t xRemain = ( BaseType_t )( pxBuffer->LENGTH - pxBuffer->uxHead ); - - *pxLength = FreeRTOS_min_BaseType( xSpace, xRemain ); - pucReturn = pxBuffer->ucArray + pxBuffer->uxHead; - } - } - - return pucReturn; - } -#endif /* ipconfigUSE_TCP */ -/*-----------------------------------------------------------*/ - -#if( ipconfigUSE_TCP == 1 ) - /* - * Send data using a TCP socket. It is not necessary to have the socket - * connected already. Outgoing data will be stored and delivered as soon as - * the socket gets connected. - */ - BaseType_t FreeRTOS_send( Socket_t xSocket, const void *pvBuffer, size_t uxDataLength, BaseType_t xFlags ) - { - BaseType_t xByteCount; - BaseType_t xBytesLeft; - FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; - TickType_t xRemainingTime; - BaseType_t xTimed = pdFALSE; - TimeOut_t xTimeOut; - BaseType_t xCloseAfterSend; - - /* Prevent compiler warnings about unused parameters. The parameter - may be used in future versions. */ - ( void ) xFlags; - - xByteCount = ( BaseType_t ) prvTCPSendCheck( pxSocket, uxDataLength ); - - if( xByteCount > 0 ) - { - /* xBytesLeft is number of bytes to send, will count to zero. */ - xBytesLeft = ( BaseType_t ) uxDataLength; - - /* xByteCount is number of bytes that can be sent now. */ - xByteCount = ( BaseType_t ) uxStreamBufferGetSpace( pxSocket->u.xTCP.txStream ); - - /* While there are still bytes to be sent. */ - while( xBytesLeft > 0 ) - { - /* If txStream has space. */ - if( xByteCount > 0 ) - { - /* Don't send more than necessary. */ - if( xByteCount > xBytesLeft ) - { - xByteCount = xBytesLeft; - } - - /* Is the close-after-send flag set and is this really the - last transmission? */ - if( ( pxSocket->u.xTCP.bits.bCloseAfterSend != pdFALSE_UNSIGNED ) && ( xByteCount == xBytesLeft ) ) - { - xCloseAfterSend = pdTRUE; - } - else - { - xCloseAfterSend = pdFALSE; - } - - /* The flag 'bCloseAfterSend' can be set before sending data - using setsockopt() - - When the last data packet is being sent out, a FIN flag will - be included to let the peer know that no more data is to be - expected. The use of 'bCloseAfterSend' is not mandatory, it - is just a faster way of transferring files (e.g. when using - FTP). */ - if( xCloseAfterSend != pdFALSE ) - { - /* Now suspend the scheduler: sending the last data and - setting bCloseRequested must be done together */ - vTaskSuspendAll(); - pxSocket->u.xTCP.bits.bCloseRequested = pdTRUE_UNSIGNED; - } - - xByteCount = ( BaseType_t ) uxStreamBufferAdd( pxSocket->u.xTCP.txStream, 0ul, ( const uint8_t * ) pvBuffer, ( size_t ) xByteCount ); - - if( xCloseAfterSend != pdFALSE ) - { - /* Now when the IP-task transmits the data, it will also - see that bCloseRequested is true and include the FIN - flag to start closure of the connection. */ - xTaskResumeAll(); - } - - /* Send a message to the IP-task so it can work on this - socket. Data is sent, let the IP-task work on it. */ - pxSocket->u.xTCP.usTimeout = 1u; - - if( xIsCallingFromIPTask() == pdFALSE ) - { - /* Only send a TCP timer event when not called from the - IP-task. */ - xSendEventToIPTask( eTCPTimerEvent ); - } - - xBytesLeft -= xByteCount; - - if( xBytesLeft == 0 ) - { - break; - } - - /* As there are still bytes left to be sent, increase the - data pointer. */ - pvBuffer = ( void * ) ( ( ( const uint8_t * ) pvBuffer) + xByteCount ); - } - - /* Not all bytes have been sent. In case the socket is marked as - blocking sleep for a while. */ - if( xTimed == pdFALSE ) - { - /* Only in the first round, check for non-blocking. */ - xRemainingTime = pxSocket->xSendBlockTime; - - #if( ipconfigUSE_CALLBACKS != 0 ) - { - if( xIsCallingFromIPTask() != pdFALSE ) - { - /* If this send function is called from within a - call-back handler it may not block, otherwise - chances would be big to get a deadlock: the IP-task - waiting for itself. */ - xRemainingTime = ( TickType_t ) 0; - } - } - #endif /* ipconfigUSE_CALLBACKS */ - - if( xRemainingTime == ( TickType_t ) 0 ) - { - break; - } - - if( ( xFlags & FREERTOS_MSG_DONTWAIT ) != 0 ) - { - break; - } - - /* Don't get here a second time. */ - xTimed = pdTRUE; - - /* Fetch the current time. */ - vTaskSetTimeOutState( &xTimeOut ); - } - else - { - /* Has the timeout been reached? */ - if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE ) - { - break; - } - } - - /* Go sleeping until down-stream events are received. */ - xEventGroupWaitBits( pxSocket->xEventGroup, eSOCKET_SEND | eSOCKET_CLOSED, - pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime ); - - xByteCount = ( BaseType_t ) uxStreamBufferGetSpace( pxSocket->u.xTCP.txStream ); - } - - /* How much was actually sent? */ - xByteCount = ( ( BaseType_t ) uxDataLength ) - xBytesLeft; - - if( xByteCount == 0 ) - { - if( pxSocket->u.xTCP.ucTCPState > eESTABLISHED ) - { - xByteCount = ( BaseType_t ) -pdFREERTOS_ERRNO_ENOTCONN; - } - else - { - if( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) - { - FreeRTOS_debug_printf( ( "FreeRTOS_send: %u -> %lxip:%d: no space\n", - pxSocket->usLocalPort, - pxSocket->u.xTCP.ulRemoteIP, - pxSocket->u.xTCP.usRemotePort ) ); - } - - xByteCount = ( BaseType_t ) -pdFREERTOS_ERRNO_ENOSPC; - } - } - } - - return xByteCount; - } - -#endif /* ipconfigUSE_TCP */ -/*-----------------------------------------------------------*/ - -#if( ipconfigUSE_TCP == 1 ) - - /* - * Request to put a socket in listen mode - */ - BaseType_t FreeRTOS_listen( Socket_t xSocket, BaseType_t xBacklog ) - { - FreeRTOS_Socket_t *pxSocket; - BaseType_t xResult = 0; - - pxSocket = ( FreeRTOS_Socket_t * ) xSocket; - - /* listen() is allowed for a valid TCP socket in Closed state and already - bound. */ - if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE ) - { - xResult = -pdFREERTOS_ERRNO_EOPNOTSUPP; - } - else if( ( pxSocket->u.xTCP.ucTCPState != eCLOSED ) && ( pxSocket->u.xTCP.ucTCPState != eCLOSE_WAIT ) ) - { - /* Socket is in a wrong state. */ - xResult = -pdFREERTOS_ERRNO_EOPNOTSUPP; - } - else - { - /* Backlog is interpreted here as "the maximum number of child - sockets. */ - pxSocket->u.xTCP.usBacklog = ( uint16_t )FreeRTOS_min_int32( ( int32_t ) 0xffff, ( int32_t ) xBacklog ); - - /* This cleaning is necessary only if a listening socket is being - reused as it might have had a previous connection. */ - if( pxSocket->u.xTCP.bits.bReuseSocket ) - { - if( pxSocket->u.xTCP.rxStream != NULL ) - { - vStreamBufferClear( pxSocket->u.xTCP.rxStream ); - } - - if( pxSocket->u.xTCP.txStream != NULL ) - { - vStreamBufferClear( pxSocket->u.xTCP.txStream ); - } - - memset( pxSocket->u.xTCP.xPacket.u.ucLastPacket, '\0', sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) ); - memset( &pxSocket->u.xTCP.xTCPWindow, '\0', sizeof( pxSocket->u.xTCP.xTCPWindow ) ); - memset( &pxSocket->u.xTCP.bits, '\0', sizeof( pxSocket->u.xTCP.bits ) ); - - /* Now set the bReuseSocket flag again, because the bits have - just been cleared. */ - pxSocket->u.xTCP.bits.bReuseSocket = pdTRUE_UNSIGNED; - } - - vTCPStateChange( pxSocket, eTCP_LISTEN ); - } - - return xResult; - } - -#endif /* ipconfigUSE_TCP */ -/*-----------------------------------------------------------*/ - -#if( ipconfigUSE_TCP == 1 ) - - /* shutdown - shut down part of a full-duplex connection */ - BaseType_t FreeRTOS_shutdown( Socket_t xSocket, BaseType_t xHow ) - { - FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; - BaseType_t xResult; - - if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE ) - { - /*_RB_ Is this comment correct? The socket is not of a type that - supports the listen() operation. */ - xResult = -pdFREERTOS_ERRNO_EOPNOTSUPP; - } - else if ( pxSocket->u.xTCP.ucTCPState != eESTABLISHED ) - { - /*_RB_ Is this comment correct? The socket is not of a type that - supports the listen() operation. */ - xResult = -pdFREERTOS_ERRNO_EOPNOTSUPP; - } - else - { - pxSocket->u.xTCP.bits.bUserShutdown = pdTRUE_UNSIGNED; - - /* Let the IP-task perform the shutdown of the connection. */ - pxSocket->u.xTCP.usTimeout = 1u; - xSendEventToIPTask( eTCPTimerEvent ); - xResult = 0; - } - (void) xHow; - - return xResult; - } - -#endif /* ipconfigUSE_TCP */ -/*-----------------------------------------------------------*/ - -#if( ipconfigUSE_TCP == 1 ) - - /* - * A TCP timer has expired, now check all TCP sockets for: - * - Active connect - * - Send a delayed ACK - * - Send new data - * - Send a keep-alive packet - * - Check for timeout (in non-connected states only) - */ - TickType_t xTCPTimerCheck( BaseType_t xWillSleep ) - { - FreeRTOS_Socket_t *pxSocket; - TickType_t xShortest = pdMS_TO_TICKS( ( TickType_t ) ipTCP_TIMER_PERIOD_MS ); - TickType_t xNow = xTaskGetTickCount(); - static TickType_t xLastTime = 0u; - TickType_t xDelta = xNow - xLastTime; - ListItem_t* pxEnd = ( ListItem_t * ) listGET_END_MARKER( &xBoundTCPSocketsList ); - ListItem_t *pxIterator = ( ListItem_t * ) listGET_HEAD_ENTRY( &xBoundTCPSocketsList ); - - xLastTime = xNow; - - if( xDelta == 0u ) - { - xDelta = 1u; - } - - while( pxIterator != pxEnd ) - { - pxSocket = ( FreeRTOS_Socket_t * )listGET_LIST_ITEM_OWNER( pxIterator ); - pxIterator = ( ListItem_t * ) listGET_NEXT( pxIterator ); - - /* Sockets with 'tmout == 0' do not need any regular attention. */ - if( pxSocket->u.xTCP.usTimeout == 0u ) - { - continue; - } - - if( xDelta < ( TickType_t ) pxSocket->u.xTCP.usTimeout ) - { - pxSocket->u.xTCP.usTimeout = ( uint16_t ) ( ( ( TickType_t ) pxSocket->u.xTCP.usTimeout ) - xDelta ); - } - else - { - int rc ; - pxSocket->u.xTCP.usTimeout = 0u; - rc = xTCPSocketCheck( pxSocket ); - - /* Within this function, the socket might want to send a delayed - ack or send out data or whatever it needs to do. */ - if( rc < 0 ) - { - /* Continue because the socket was deleted. */ - continue; - } - } - - /* In xEventBits the driver may indicate that the socket has - important events for the user. These are only done just before the - IP-task goes to sleep. */ - if( pxSocket->xEventBits != 0u ) - { - if( xWillSleep != pdFALSE ) - { - /* The IP-task is about to go to sleep, so messages can be - sent to the socket owners. */ - vSocketWakeUpUser( pxSocket ); - } - else - { - /* Or else make sure this will be called again to wake-up - the sockets' owner. */ - xShortest = ( TickType_t ) 0; - } - } - - if( ( pxSocket->u.xTCP.usTimeout != 0u ) && ( xShortest > ( TickType_t ) pxSocket->u.xTCP.usTimeout ) ) - { - xShortest = ( TickType_t ) pxSocket->u.xTCP.usTimeout; - } - } - - return xShortest; - } - -#endif /* ipconfigUSE_TCP */ -/*-----------------------------------------------------------*/ - -#if( ipconfigUSE_TCP == 1 ) - - /* - * TCP: as multiple sockets may be bound to the same local port number - * looking up a socket is a little more complex: - * Both a local port, and a remote port and IP address are being used - * For a socket in listening mode, the remote port and IP address are both 0 - */ - FreeRTOS_Socket_t *pxTCPSocketLookup( uint32_t ulLocalIP, UBaseType_t uxLocalPort, uint32_t ulRemoteIP, UBaseType_t uxRemotePort ) - { - ListItem_t *pxIterator; - FreeRTOS_Socket_t *pxResult = NULL, *pxListenSocket = NULL; - MiniListItem_t *pxEnd = ( MiniListItem_t* )listGET_END_MARKER( &xBoundTCPSocketsList ); - - /* Parameter not yet supported. */ - ( void ) ulLocalIP; - - for( pxIterator = ( ListItem_t * ) listGET_NEXT( pxEnd ); - pxIterator != ( ListItem_t * ) pxEnd; - pxIterator = ( ListItem_t * ) listGET_NEXT( pxIterator ) ) - { - FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator ); - - if( pxSocket->usLocalPort == ( uint16_t ) uxLocalPort ) - { - if( pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN ) - { - /* If this is a socket listening to uxLocalPort, remember it - in case there is no perfect match. */ - pxListenSocket = pxSocket; - } - else if( ( pxSocket->u.xTCP.usRemotePort == ( uint16_t ) uxRemotePort ) && ( pxSocket->u.xTCP.ulRemoteIP == ulRemoteIP ) ) - { - /* For sockets not in listening mode, find a match with - xLocalPort, ulRemoteIP AND xRemotePort. */ - pxResult = pxSocket; - break; - } - } - } - if( pxResult == NULL ) - { - /* An exact match was not found, maybe a listening socket was - found. */ - pxResult = pxListenSocket; - } - - return pxResult; - } - -#endif /* ipconfigUSE_TCP */ -/*-----------------------------------------------------------*/ - -#if( ipconfigUSE_TCP == 1 ) - - const struct xSTREAM_BUFFER *FreeRTOS_get_rx_buf( Socket_t xSocket ) - { - FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * )xSocket; - struct xSTREAM_BUFFER *pxReturn = NULL; - - /* Confirm that this is a TCP socket before dereferencing structure - member pointers. */ - if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdFALSE ) == pdTRUE ) - { - pxReturn = pxSocket->u.xTCP.rxStream; - } - - return pxReturn; - } - -#endif /* ipconfigUSE_TCP */ -/*-----------------------------------------------------------*/ - -#if( ipconfigUSE_TCP == 1 ) - - static StreamBuffer_t *prvTCPCreateStream ( FreeRTOS_Socket_t *pxSocket, BaseType_t xIsInputStream ) - { - StreamBuffer_t *pxBuffer; - size_t uxLength; - size_t uxSize; - - /* Now that a stream is created, the maximum size is fixed before - creation, it could still be changed with setsockopt(). */ - if( xIsInputStream != pdFALSE ) - { - uxLength = pxSocket->u.xTCP.uxRxStreamSize; - - if( pxSocket->u.xTCP.uxLittleSpace == 0ul ) - { - pxSocket->u.xTCP.uxLittleSpace = ( sock20_PERCENT * pxSocket->u.xTCP.uxRxStreamSize ) / sock100_PERCENT; - } - - if( pxSocket->u.xTCP.uxEnoughSpace == 0ul ) - { - pxSocket->u.xTCP.uxEnoughSpace = ( sock80_PERCENT * pxSocket->u.xTCP.uxRxStreamSize ) / sock100_PERCENT; - } - } - else - { - uxLength = pxSocket->u.xTCP.uxTxStreamSize; - } - - /* Add an extra 4 (or 8) bytes. */ - uxLength += sizeof( size_t ); - - /* And make the length a multiple of sizeof( size_t ). */ - uxLength &= ~( sizeof( size_t ) - 1u ); - - uxSize = sizeof( *pxBuffer ) - sizeof( pxBuffer->ucArray ) + uxLength; - - pxBuffer = ( StreamBuffer_t * )pvPortMallocLarge( uxSize ); - - if( pxBuffer == NULL ) - { - FreeRTOS_debug_printf( ( "prvTCPCreateStream: malloc failed\n" ) ); - pxSocket->u.xTCP.bits.bMallocError = pdTRUE_UNSIGNED; - vTCPStateChange( pxSocket, eCLOSE_WAIT ); - } - else - { - /* Clear the markers of the stream */ - memset( pxBuffer, '\0', sizeof( *pxBuffer ) - sizeof( pxBuffer->ucArray ) ); - pxBuffer->LENGTH = ( size_t ) uxLength ; - - if( xTCPWindowLoggingLevel != 0 ) - { - FreeRTOS_debug_printf( ( "prvTCPCreateStream: %cxStream created %lu bytes (total %lu)\n", xIsInputStream ? 'R' : 'T', uxLength, uxSize ) ); - } - - if( xIsInputStream != 0 ) - { - pxSocket->u.xTCP.rxStream = pxBuffer; - } - else - { - pxSocket->u.xTCP.txStream = pxBuffer; - } - } - - return pxBuffer; - } - -#endif /* ipconfigUSE_TCP */ -/*-----------------------------------------------------------*/ - -#if( ipconfigUSE_TCP == 1 ) - - /* - * Add data to the RxStream. When uxOffset > 0, data has come in out-of-order - * and will be put in front of the head so it can not be popped by the user. - */ - int32_t lTCPAddRxdata( FreeRTOS_Socket_t *pxSocket, size_t uxOffset, const uint8_t *pcData, uint32_t ulByteCount ) - { - StreamBuffer_t *pxStream = pxSocket->u.xTCP.rxStream; - int32_t xResult; - #if( ipconfigUSE_CALLBACKS == 1 ) - BaseType_t bHasHandler = ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleReceive ); - const uint8_t *pucBuffer = NULL; - #endif /* ipconfigUSE_CALLBACKS */ - - /* int32_t uxStreamBufferAdd( pxBuffer, uxOffset, pucData, aCount ) - if( pucData != NULL ) copy data the the buffer - if( pucData == NULL ) no copying, just advance rxHead - if( uxOffset != 0 ) Just store data which has come out-of-order - if( uxOffset == 0 ) Also advance rxHead */ - if( pxStream == NULL ) - { - pxStream = prvTCPCreateStream( pxSocket, pdTRUE ); - if( pxStream == NULL ) - { - return -1; - } - } - - #if( ipconfigUSE_CALLBACKS == 1 ) - { - if( ( bHasHandler != pdFALSE ) && ( uxStreamBufferGetSize( pxStream ) == 0u ) && ( uxOffset == 0ul ) && ( pcData != NULL ) ) - { - /* Data can be passed directly to the user */ - pucBuffer = pcData; - - /* Zero-copy for call-back: no need to add the bytes to the - stream, only the pointer will be advanced by uxStreamBufferAdd(). */ - pcData = NULL; - } - } - #endif /* ipconfigUSE_CALLBACKS */ - - xResult = ( int32_t ) uxStreamBufferAdd( pxStream, uxOffset, pcData, ( size_t ) ulByteCount ); - - #if( ipconfigHAS_DEBUG_PRINTF != 0 ) - { - if( xResult != ( int32_t ) ulByteCount ) - { - FreeRTOS_debug_printf( ( "lTCPAddRxdata: at %ld: %ld/%lu bytes (tail %lu head %lu space %lu front %lu)\n", - uxOffset, xResult, ulByteCount, - pxStream->uxTail, - pxStream->uxHead, - uxStreamBufferFrontSpace( pxStream ), - pxStream->uxFront ) ); - } - } - #endif /* ipconfigHAS_DEBUG_PRINTF */ - - if( uxOffset == 0u ) - { - /* Data is being added to rxStream at the head (offs = 0) */ - #if( ipconfigUSE_CALLBACKS == 1 ) - if( bHasHandler != pdFALSE ) - { - /* The socket owner has installed an OnReceive handler. Pass the - Rx data, without copying from the rxStream, to the user. */ - for (;;) - { - uint8_t *ucReadPtr = NULL; - uint32_t ulCount; - if( pucBuffer != NULL ) - { - ucReadPtr = ( uint8_t * )pucBuffer; - ulCount = ulByteCount; - pucBuffer = NULL; - } - else - { - ulCount = ( uint32_t ) uxStreamBufferGetPtr( pxStream, &( ucReadPtr ) ); - } - - if( ulCount == 0ul ) - { - break; - } - - pxSocket->u.xTCP.pxHandleReceive( ( Socket_t )pxSocket, ( void* )ucReadPtr, ( size_t ) ulCount ); - uxStreamBufferGet( pxStream, 0ul, NULL, ( size_t ) ulCount, pdFALSE ); - } - } else - #endif /* ipconfigUSE_CALLBACKS */ - { - /* See if running out of space. */ - if( pxSocket->u.xTCP.bits.bLowWater == pdFALSE_UNSIGNED ) - { - size_t uxFrontSpace = uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream ); - if( uxFrontSpace <= pxSocket->u.xTCP.uxLittleSpace ) - { - pxSocket->u.xTCP.bits.bLowWater = pdTRUE_UNSIGNED; - pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED; - - /* bLowWater was reached, send the changed window size. */ - pxSocket->u.xTCP.usTimeout = 1u; - xSendEventToIPTask( eTCPTimerEvent ); - } - } - - /* New incoming data is available, wake up the user. User's - semaphores will be set just before the IP-task goes asleep. */ - pxSocket->xEventBits |= eSOCKET_RECEIVE; - - #if ipconfigSUPPORT_SELECT_FUNCTION == 1 - { - if( ( pxSocket->xSelectBits & eSELECT_READ ) != 0 ) - { - pxSocket->xEventBits |= ( eSELECT_READ << SOCKET_EVENT_BIT_COUNT ); - } - } - #endif - } - } - - return xResult; - } - -#endif /* ipconfigUSE_TCP */ -/*-----------------------------------------------------------*/ - -#if( ipconfigUSE_TCP == 1 ) - - /* Function to get the remote address and IP port */ - BaseType_t FreeRTOS_GetRemoteAddress( Socket_t xSocket, struct freertos_sockaddr *pxAddress ) - { - FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; - BaseType_t xResult; - - if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) - { - xResult = -pdFREERTOS_ERRNO_EINVAL; - } - else - { - /* BSD style sockets communicate IP and port addresses in network - byte order. - - IP address of remote machine. */ - pxAddress->sin_addr = FreeRTOS_htonl ( pxSocket->u.xTCP.ulRemoteIP ); - - /* Port on remote machine. */ - pxAddress->sin_port = FreeRTOS_htons ( pxSocket->u.xTCP.usRemotePort ); - - xResult = ( BaseType_t ) sizeof( ( *pxAddress ) ); - } - - return xResult; - } - -#endif /* ipconfigUSE_TCP */ - -/*-----------------------------------------------------------*/ - -#if( ipconfigUSE_TCP == 1 ) - - /* Returns the number of bytes that may be added to txStream */ - BaseType_t FreeRTOS_maywrite( Socket_t xSocket ) - { - FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; - BaseType_t xResult; - - if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) - { - xResult = -pdFREERTOS_ERRNO_EINVAL; - } - else if( pxSocket->u.xTCP.ucTCPState != eESTABLISHED ) - { - if( ( pxSocket->u.xTCP.ucTCPState < eCONNECT_SYN ) || ( pxSocket->u.xTCP.ucTCPState > eESTABLISHED ) ) - { - xResult = -1; - } - else - { - xResult = 0; - } - } - else if( pxSocket->u.xTCP.txStream == NULL ) - { - xResult = ( BaseType_t ) pxSocket->u.xTCP.uxTxStreamSize; - } - else - { - xResult = ( BaseType_t ) uxStreamBufferGetSpace( pxSocket->u.xTCP.txStream ); - } - - return xResult; - } - -#endif /* ipconfigUSE_TCP */ -/*-----------------------------------------------------------*/ - -#if( ipconfigUSE_TCP ==1 ) - - BaseType_t FreeRTOS_tx_space( Socket_t xSocket ) - { - FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; - BaseType_t xReturn; - - if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) - { - xReturn = -pdFREERTOS_ERRNO_EINVAL; - } - else - { - if( pxSocket->u.xTCP.txStream != NULL ) - { - xReturn = ( BaseType_t ) uxStreamBufferGetSpace ( pxSocket->u.xTCP.txStream ); - } - else - { - xReturn = ( BaseType_t ) pxSocket->u.xTCP.uxTxStreamSize; - } - } - - return xReturn; - } - -#endif /* ipconfigUSE_TCP */ -/*-----------------------------------------------------------*/ - -#if( ipconfigUSE_TCP == 1 ) - - BaseType_t FreeRTOS_tx_size( Socket_t xSocket ) - { - FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; - BaseType_t xReturn; - - if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) - { - xReturn = -pdFREERTOS_ERRNO_EINVAL; - } - else - { - if( pxSocket->u.xTCP.txStream != NULL ) - { - xReturn = ( BaseType_t ) uxStreamBufferGetSize ( pxSocket->u.xTCP.txStream ); - } - else - { - xReturn = 0; - } - } - - return xReturn; - } - -#endif /* ipconfigUSE_TCP */ -/*-----------------------------------------------------------*/ - -#if( ipconfigUSE_TCP == 1 ) - - /* Returns pdTRUE if TCP socket is connected. */ - BaseType_t FreeRTOS_issocketconnected( Socket_t xSocket ) - { - FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; - BaseType_t xReturn = pdFALSE; - - if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) - { - xReturn = -pdFREERTOS_ERRNO_EINVAL; - } - else - { - if( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) - { - if( pxSocket->u.xTCP.ucTCPState < eCLOSE_WAIT ) - { - xReturn = pdTRUE; - } - } - } - - return xReturn; - } - -#endif /* ipconfigUSE_TCP */ -/*-----------------------------------------------------------*/ - -#if( ipconfigUSE_TCP == 1 ) - - /* returns the actual size of MSS being used */ - BaseType_t FreeRTOS_mss( Socket_t xSocket ) - { - FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; - BaseType_t xReturn; - - if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) - { - xReturn = -pdFREERTOS_ERRNO_EINVAL; - } - else - { - /* usCurMSS is declared as uint16_t to save space. FreeRTOS_mss() - will often be used in signed native-size expressions cast it to - BaseType_t. */ - xReturn = ( BaseType_t ) ( pxSocket->u.xTCP.usCurMSS ); - } - - return xReturn; - } - -#endif /* ipconfigUSE_TCP */ -/*-----------------------------------------------------------*/ - -#if( ipconfigUSE_TCP == 1 ) - - /* HT: for internal use only: return the connection status */ - BaseType_t FreeRTOS_connstatus( Socket_t xSocket ) - { - FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; - BaseType_t xReturn; - - if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) - { - xReturn = -pdFREERTOS_ERRNO_EINVAL; - } - else - { - /* Cast it to BaseType_t */ - xReturn = ( BaseType_t ) ( pxSocket->u.xTCP.ucTCPState ); - } - - return xReturn; - } - -#endif /* ipconfigUSE_TCP */ -/*-----------------------------------------------------------*/ - -#if( ipconfigUSE_TCP == 1 ) - - /* - * Returns the number of bytes which can be read. - */ - BaseType_t FreeRTOS_rx_size( Socket_t xSocket ) - { - FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; - BaseType_t xReturn; - - if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) - { - xReturn = -pdFREERTOS_ERRNO_EINVAL; - } - else if( pxSocket->u.xTCP.rxStream != NULL ) - { - xReturn = ( BaseType_t ) uxStreamBufferGetSize( pxSocket->u.xTCP.rxStream ); - } - else - { - xReturn = 0; - } - - return xReturn; - } - -#endif /* ipconfigUSE_TCP */ -/*-----------------------------------------------------------*/ - -#if( ipconfigUSE_TCP == 1 ) - - void FreeRTOS_netstat( void ) - { - IPStackEvent_t xAskEvent; - - /* Ask the IP-task to call vTCPNetStat() - * to avoid accessing xBoundTCPSocketsList - */ - xAskEvent.eEventType = eTCPNetStat; - xAskEvent.pvData = ( void * ) NULL; - xSendEventStructToIPTask( &xAskEvent, 1000u ); - } - -#endif /* ipconfigUSE_TCP */ -/*-----------------------------------------------------------*/ - -#if( ( ipconfigHAS_PRINTF != 0 ) && ( ipconfigUSE_TCP == 1 ) ) - - void vTCPNetStat( void ) - { - /* Show a simple listing of all created sockets and their connections */ - ListItem_t *pxIterator; - BaseType_t count = 0; - - if( listLIST_IS_INITIALISED( &xBoundTCPSocketsList ) == pdFALSE ) - { - FreeRTOS_printf( ( "PLUS-TCP not initialized\n" ) ); - } - else - { - FreeRTOS_printf( ( "Prot Port IP-Remote : Port R/T Status Alive tmout Child\n" ) ); - for( pxIterator = ( ListItem_t * ) listGET_HEAD_ENTRY( &xBoundTCPSocketsList ); - pxIterator != ( ListItem_t * ) listGET_END_MARKER( &xBoundTCPSocketsList ); - pxIterator = ( ListItem_t * ) listGET_NEXT( pxIterator ) ) - { - FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator ); - #if( ipconfigTCP_KEEP_ALIVE == 1 ) - TickType_t age = xTaskGetTickCount() - pxSocket->u.xTCP.xLastAliveTime; - #else - TickType_t age = 0u; - #endif - #if( ipconfigUSE_CALLBACKS == 1 ) - void *pxHandleReceive = (void*)pxSocket->u.xTCP.pxHandleReceive; - #else - void *pxHandleReceive = (void*)NULL; - #endif - char ucChildText[16] = ""; - if (pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN) - { - const int32_t copied_len = snprintf( ucChildText, sizeof( ucChildText ), " %d/%d", - ( int ) pxSocket->u.xTCP.usChildCount, - ( int ) pxSocket->u.xTCP.usBacklog); - /* These should never evaluate to false since the buffers are both shorter than 5-6 characters (<=65535) */ - configASSERT( copied_len >= 0 ); - configASSERT( copied_len < sizeof( ucChildText ) ); - } - FreeRTOS_printf( ( "TCP %5d %-16lxip:%5d %d/%d %-13.13s %6lu %6u%s\n", - pxSocket->usLocalPort, /* Local port on this machine */ - pxSocket->u.xTCP.ulRemoteIP, /* IP address of remote machine */ - pxSocket->u.xTCP.usRemotePort, /* Port on remote machine */ - pxSocket->u.xTCP.rxStream != NULL, - pxSocket->u.xTCP.txStream != NULL, - FreeRTOS_GetTCPStateName( pxSocket->u.xTCP.ucTCPState ), - (age > 999999 ? 999999 : age), /* Format 'age' for printing */ - pxSocket->u.xTCP.usTimeout, - ucChildText ) ); - /* Remove compiler warnings if FreeRTOS_debug_printf() is not defined. */ - ( void ) pxHandleReceive; - count++; - } - - for( pxIterator = ( ListItem_t * ) listGET_HEAD_ENTRY( &xBoundUDPSocketsList ); - pxIterator != ( ListItem_t * ) listGET_END_MARKER( &xBoundUDPSocketsList ); - pxIterator = ( ListItem_t * ) listGET_NEXT( pxIterator ) ) - { - /* Local port on this machine */ - FreeRTOS_printf( ( "UDP Port %5u\n", - FreeRTOS_ntohs( listGET_LIST_ITEM_VALUE( pxIterator ) ) ) ); - count++; - } - - FreeRTOS_printf( ( "FreeRTOS_netstat: %lu sockets %lu < %lu < %d buffers free\n", - count, - uxGetMinimumFreeNetworkBuffers( ), - uxGetNumberOfFreeNetworkBuffers( ), - ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ) ); - } - } - -#endif /* ( ( ipconfigHAS_PRINTF != 0 ) && ( ipconfigUSE_TCP == 1 ) ) */ -/*-----------------------------------------------------------*/ - -#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) - - void vSocketSelect( SocketSelect_t *pxSocketSet ) - { - BaseType_t xRound; - EventBits_t xSocketBits, xBitsToClear; - #if ipconfigUSE_TCP == 1 - BaseType_t xLastRound = 1; - #else - BaseType_t xLastRound = 0; - #endif - - /* These flags will be switched on after checking the socket status. */ - EventBits_t xGroupBits = 0; - pxSocketSet->pxSocket = NULL; - - for( xRound = 0; xRound <= xLastRound; xRound++ ) - { - const ListItem_t *pxIterator; - const MiniListItem_t *pxEnd; - if( xRound == 0 ) - { - pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( &xBoundUDPSocketsList ); - } - #if ipconfigUSE_TCP == 1 - else - { - pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( &xBoundTCPSocketsList ); - } - #endif /* ipconfigUSE_TCP == 1 */ - for( pxIterator = ( const ListItem_t * ) ( listGET_NEXT( pxEnd ) ); - pxIterator != ( const ListItem_t * ) pxEnd; - pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) ) - { - FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator ); - if( pxSocket->pxSocketSet != pxSocketSet ) - { - /* Socket does not belong to this select group. */ - continue; - } - xSocketBits = 0; - - #if( ipconfigUSE_TCP == 1 ) - if( pxSocket->ucProtocol == FREERTOS_IPPROTO_TCP ) - { - /* Check if the socket has already been accepted by the - owner. If not, it is useless to return it from a - select(). */ - BaseType_t bAccepted = pdFALSE; - - if( pxSocket->u.xTCP.bits.bPassQueued == pdFALSE_UNSIGNED ) - { - if( pxSocket->u.xTCP.bits.bPassAccept == pdFALSE_UNSIGNED ) - { - bAccepted = pdTRUE; - } - } - - /* Is the set owner interested in READ events? */ - if( ( pxSocket->xSelectBits & eSELECT_READ ) != 0 ) - { - if( pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN ) - { - if( ( pxSocket->u.xTCP.pxPeerSocket != NULL ) && ( pxSocket->u.xTCP.pxPeerSocket->u.xTCP.bits.bPassAccept != 0 ) ) - { - xSocketBits |= eSELECT_READ; - } - } - else if( ( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED ) && ( pxSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) ) - { - /* This socket has the re-use flag. After connecting it turns into - aconnected socket. Set the READ event, so that accept() will be called. */ - xSocketBits |= eSELECT_READ; - } - else if( ( bAccepted != 0 ) && ( FreeRTOS_recvcount( pxSocket ) > 0 ) ) - { - xSocketBits |= eSELECT_READ; - } - } - /* Is the set owner interested in EXCEPTION events? */ - if( ( pxSocket->xSelectBits & eSELECT_EXCEPT ) != 0 ) - { - if( ( pxSocket->u.xTCP.ucTCPState == eCLOSE_WAIT ) || ( pxSocket->u.xTCP.ucTCPState == eCLOSED ) ) - { - xSocketBits |= eSELECT_EXCEPT; - } - } - - /* Is the set owner interested in WRITE events? */ - if( ( pxSocket->xSelectBits & eSELECT_WRITE ) != 0 ) - { - BaseType_t bMatch = pdFALSE; - - if( bAccepted != 0 ) - { - if( FreeRTOS_tx_space( pxSocket ) > 0 ) - { - bMatch = pdTRUE; - } - } - - if( bMatch == pdFALSE ) - { - if( ( pxSocket->u.xTCP.bits.bConnPrepared != pdFALSE_UNSIGNED ) && - ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) && - ( pxSocket->u.xTCP.bits.bConnPassed == pdFALSE_UNSIGNED ) ) - { - pxSocket->u.xTCP.bits.bConnPassed = pdTRUE_UNSIGNED; - bMatch = pdTRUE; - } - } - - if( bMatch != pdFALSE ) - { - xSocketBits |= eSELECT_WRITE; - } - } - } - else - #endif /* ipconfigUSE_TCP == 1 */ - { - /* Select events for UDP are simpler. */ - if( ( ( pxSocket->xSelectBits & eSELECT_READ ) != 0 ) && - ( listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ) > 0U ) ) - { - xSocketBits |= eSELECT_READ; - } - /* The WRITE and EXCEPT bits are not used for UDP */ - } /* if( pxSocket->ucProtocol == FREERTOS_IPPROTO_TCP ) */ - - /* Each socket keeps its own event flags, which are looked-up - by FreeRTOS_FD_ISSSET() */ - pxSocket->xSocketBits = xSocketBits; - - /* The ORed value will be used to set the bits in the event - group. */ - xGroupBits |= xSocketBits; - - } /* for( pxIterator ... ) */ - } /* for( xRound = 0; xRound <= xLastRound; xRound++ ) */ - - xBitsToClear = xEventGroupGetBits( pxSocketSet->xSelectGroup ); - - /* Now set the necessary bits. */ - xBitsToClear = ( xBitsToClear & ~xGroupBits ) & eSELECT_ALL; - - #if( ipconfigSUPPORT_SIGNALS != 0 ) - { - /* Maybe the socketset was signalled, but don't - clear the 'eSELECT_INTR' bit here, as it will be used - and cleared in FreeRTOS_select(). */ - xBitsToClear &= ( EventBits_t ) ~eSELECT_INTR; - } - #endif /* ipconfigSUPPORT_SIGNALS */ - - if( xBitsToClear != 0 ) - { - xEventGroupClearBits( pxSocketSet->xSelectGroup, xBitsToClear ); - } - - /* Now include eSELECT_CALL_IP to wakeup the caller. */ - xEventGroupSetBits( pxSocketSet->xSelectGroup, xGroupBits | eSELECT_CALL_IP ); - } - -#endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */ -/*-----------------------------------------------------------*/ - -#if( ipconfigSUPPORT_SIGNALS != 0 ) - - /* Send a signal to the task which reads from this socket. */ - BaseType_t FreeRTOS_SignalSocket( Socket_t xSocket ) - { - FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; - BaseType_t xReturn; - - if( pxSocket == NULL ) - { - xReturn = -pdFREERTOS_ERRNO_EINVAL; - } - else - #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) - if( ( pxSocket->pxSocketSet != NULL ) && ( pxSocket->pxSocketSet->xSelectGroup != NULL ) ) - { - xEventGroupSetBits( pxSocket->pxSocketSet->xSelectGroup, eSELECT_INTR ); - xReturn = 0; - } - else - #endif /* ipconfigSUPPORT_SELECT_FUNCTION */ - if( pxSocket->xEventGroup != NULL ) - { - xEventGroupSetBits( pxSocket->xEventGroup, eSOCKET_INTR ); - xReturn = 0; - } - else - { - xReturn = -pdFREERTOS_ERRNO_EINVAL; - } - - return xReturn; - } - -#endif /* ipconfigSUPPORT_SIGNALS */ -/*-----------------------------------------------------------*/ - -#if( ipconfigSUPPORT_SIGNALS != 0 ) - - /* Send a signal to the task which reads from this socket (FromISR version). */ - BaseType_t FreeRTOS_SignalSocketFromISR( Socket_t xSocket, BaseType_t *pxHigherPriorityTaskWoken ) - { - FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; - BaseType_t xReturn; - IPStackEvent_t xEvent; - extern QueueHandle_t xNetworkEventQueue; - - configASSERT( pxSocket != NULL ); - configASSERT( pxSocket->ucProtocol == FREERTOS_IPPROTO_TCP ); - configASSERT( pxSocket->xEventGroup ); - - xEvent.eEventType = eSocketSignalEvent; - xEvent.pvData = ( void * )pxSocket; - - /* The IP-task will call FreeRTOS_SignalSocket for this socket. */ - xReturn = xQueueSendToBackFromISR( xNetworkEventQueue, &xEvent, pxHigherPriorityTaskWoken ); - - return xReturn; - } - -#endif /* ipconfigSUPPORT_SIGNALS */ -/*-----------------------------------------------------------*/ +/* + * FreeRTOS+TCP V2.2.0 + * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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 + */ + +/* Standard includes. */ +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_UDP_IP.h" +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_IP_Private.h" +#include "FreeRTOS_DNS.h" +#include "NetworkBufferManagement.h" + +/* The ItemValue of the sockets xBoundSocketListItem member holds the socket's +port number. */ +#define socketSET_SOCKET_PORT( pxSocket, usPort ) listSET_LIST_ITEM_VALUE( ( &( ( pxSocket )->xBoundSocketListItem ) ), ( usPort ) ) +#define socketGET_SOCKET_PORT( pxSocket ) listGET_LIST_ITEM_VALUE( ( &( ( pxSocket )->xBoundSocketListItem ) ) ) + +/* Test if a socket it bound which means it is either included in +xBoundUDPSocketsList or xBoundTCPSocketsList */ +#define socketSOCKET_IS_BOUND( pxSocket ) ( listLIST_ITEM_CONTAINER( & ( pxSocket )->xBoundSocketListItem ) != NULL ) + +/* If FreeRTOS_sendto() is called on a socket that is not bound to a port +number then, depending on the FreeRTOSIPConfig.h settings, it might be that a +port number is automatically generated for the socket. Automatically generated +port numbers will be between socketAUTO_PORT_ALLOCATION_START_NUMBER and +0xffff. + +Per https://tools.ietf.org/html/rfc6056, "the dynamic ports consist of the range +49152-65535. However, ephemeral port selection algorithms should use the whole +range 1024-65535" excluding those already in use (inbound or outbound). */ +#if !defined( socketAUTO_PORT_ALLOCATION_START_NUMBER ) + #define socketAUTO_PORT_ALLOCATION_START_NUMBER ( ( uint16_t ) 0x0400 ) +#endif + +#define socketAUTO_PORT_ALLOCATION_MAX_NUMBER ( ( uint16_t ) 0xffff ) + +/* The number of octets that make up an IP address. */ +#define socketMAX_IP_ADDRESS_OCTETS 4u + +/* A block time of 0 simply means "don't block". */ +#define socketDONT_BLOCK ( ( TickType_t ) 0 ) + +#if( ( ipconfigUSE_TCP == 1 ) && !defined( ipTCP_TIMER_PERIOD_MS ) ) + #define ipTCP_TIMER_PERIOD_MS ( 1000 ) +#endif + +/* The next private port number to use when binding a client socket is stored in +the usNextPortToUse[] array - which has either 1 or two indexes depending on +whether TCP is being supported. */ +#if( ipconfigUSE_TCP == 1 ) + #define socketPROTOCOL_COUNT 2 +#else + #define socketPROTOCOL_COUNT 1 +#endif + +/* Indexes into the usNextPortToUse[] array for UDP and TCP sockets +respectively. */ +#define socketNEXT_UDP_PORT_NUMBER_INDEX 0 +#define socketNEXT_TCP_PORT_NUMBER_INDEX 1 + +/* Some helper macro's for defining the 20/80 % limits of uxLittleSpace / uxEnoughSpace. */ +#define sock20_PERCENT 20 +#define sock80_PERCENT 80 +#define sock100_PERCENT 100 + + +/*-----------------------------------------------------------*/ + +/* + * Allocate the next port number from the private allocation range. + * TCP and UDP each have their own series of port numbers + * ulProtocol is either ipPROTOCOL_UDP or ipPROTOCOL_TCP + */ +static uint16_t prvGetPrivatePortNumber( BaseType_t xProtocol ); + +/* + * Return the list item from within pxList that has an item value of + * xWantedItemValue. If there is no such list item return NULL. + */ +static const ListItem_t * pxListFindListItemWithValue( const List_t *pxList, TickType_t xWantedItemValue ); + +/* + * Return pdTRUE only if pxSocket is valid and bound, as far as can be + * determined. + */ +static BaseType_t prvValidSocket( FreeRTOS_Socket_t *pxSocket, BaseType_t xProtocol, BaseType_t xIsBound ); + +/* + * Before creating a socket, check the validity of the parameters used + * and find the size of the socket space, which is different for UDP and TCP + */ +static BaseType_t prvDetermineSocketSize( BaseType_t xDomain, BaseType_t xType, BaseType_t xProtocol, size_t *pxSocketSize ); + +#if( ipconfigUSE_TCP == 1 ) + /* + * Create a txStream or a rxStream, depending on the parameter 'xIsInputStream' + */ + static StreamBuffer_t *prvTCPCreateStream (FreeRTOS_Socket_t *pxSocket, BaseType_t xIsInputStream ); +#endif /* ipconfigUSE_TCP == 1 */ + +#if( ipconfigUSE_TCP == 1 ) + /* + * Called from FreeRTOS_send(): some checks which will be done before + * sending a TCP packed. + */ + static int32_t prvTCPSendCheck( FreeRTOS_Socket_t *pxSocket, size_t xDataLength ); +#endif /* ipconfigUSE_TCP */ + +#if( ipconfigUSE_TCP == 1 ) + /* + * When a child socket gets closed, make sure to update the child-count of the parent + */ + static void prvTCPSetSocketCount( FreeRTOS_Socket_t *pxSocketToDelete ); +#endif /* ipconfigUSE_TCP == 1 */ + +#if( ipconfigUSE_TCP == 1 ) + /* + * Called from FreeRTOS_connect(): make some checks and if allowed, send a + * message to the IP-task to start connecting to a remote socket + */ + static BaseType_t prvTCPConnectStart( FreeRTOS_Socket_t *pxSocket, struct freertos_sockaddr *pxAddress ); +#endif /* ipconfigUSE_TCP */ + +#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) + + /* Executed by the IP-task, it will check all sockets belonging to a set */ + static FreeRTOS_Socket_t *prvFindSelectedSocket( SocketSelect_t *pxSocketSet ); + +#endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */ +/*-----------------------------------------------------------*/ + +/* The list that contains mappings between sockets and port numbers. Accesses +to this list must be protected by critical sections of one kind or another. */ +List_t xBoundUDPSocketsList; + +#if ipconfigUSE_TCP == 1 + List_t xBoundTCPSocketsList; +#endif /* ipconfigUSE_TCP == 1 */ + +/*-----------------------------------------------------------*/ + +static BaseType_t prvValidSocket( FreeRTOS_Socket_t *pxSocket, BaseType_t xProtocol, BaseType_t xIsBound ) +{ +BaseType_t xReturn = pdTRUE; + + if( ( pxSocket == NULL ) || ( pxSocket == FREERTOS_INVALID_SOCKET ) ) + { + xReturn = pdFALSE; + } + else if( ( xIsBound != pdFALSE ) && ( socketSOCKET_IS_BOUND( pxSocket ) == pdFALSE ) ) + { + /* The caller expects the socket to be bound, but it isn't. */ + xReturn = pdFALSE; + } + else if( pxSocket->ucProtocol != ( uint8_t ) xProtocol ) + { + /* Socket has a wrong type (UDP != TCP). */ + xReturn = pdFALSE; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t vNetworkSocketsInit( void ) +{ + vListInitialise( &xBoundUDPSocketsList ); + + #if( ipconfigUSE_TCP == 1 ) + { + vListInitialise( &xBoundTCPSocketsList ); + } + #endif /* ipconfigUSE_TCP == 1 */ + + return pdTRUE; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvDetermineSocketSize( BaseType_t xDomain, BaseType_t xType, BaseType_t xProtocol, size_t *pxSocketSize ) +{ +BaseType_t xReturn = pdPASS; +FreeRTOS_Socket_t *pxSocket; + + /* Asserts must not appear before it has been determined that the network + task is ready - otherwise the asserts will fail. */ + if( xIPIsNetworkTaskReady() == pdFALSE ) + { + xReturn = pdFAIL; + } + else + { + /* Only Ethernet is currently supported. */ + configASSERT( xDomain == FREERTOS_AF_INET ); + + /* Check if the UDP socket-list has been initialised. */ + configASSERT( listLIST_IS_INITIALISED( &xBoundUDPSocketsList ) ); + #if( ipconfigUSE_TCP == 1 ) + { + /* Check if the TCP socket-list has been initialised. */ + configASSERT( listLIST_IS_INITIALISED( &xBoundTCPSocketsList ) ); + } + #endif /* ipconfigUSE_TCP == 1 */ + + if( xProtocol == FREERTOS_IPPROTO_UDP ) + { + if( xType != FREERTOS_SOCK_DGRAM ) + { + xReturn = pdFAIL; + configASSERT( xReturn ); + } + /* In case a UDP socket is created, do not allocate space for TCP data. */ + *pxSocketSize = ( sizeof( *pxSocket ) - sizeof( pxSocket->u ) ) + sizeof( pxSocket->u.xUDP ); + } +#if( ipconfigUSE_TCP == 1 ) + else if( xProtocol == FREERTOS_IPPROTO_TCP ) + { + if( xType != FREERTOS_SOCK_STREAM ) + { + xReturn = pdFAIL; + configASSERT( xReturn ); + } + + *pxSocketSize = ( sizeof( *pxSocket ) - sizeof( pxSocket->u ) ) + sizeof( pxSocket->u.xTCP ); + } +#endif /* ipconfigUSE_TCP == 1 */ + else + { + xReturn = pdFAIL; + configASSERT( xReturn ); + } + } + /* In case configASSERT() is not used */ + ( void )xDomain; + return xReturn; +} +/*-----------------------------------------------------------*/ + +/* FreeRTOS_socket() allocates and initiates a socket */ +Socket_t FreeRTOS_socket( BaseType_t xDomain, BaseType_t xType, BaseType_t xProtocol ) +{ +FreeRTOS_Socket_t *pxSocket; +size_t uxSocketSize; +EventGroupHandle_t xEventGroup; +Socket_t xReturn; + + if( prvDetermineSocketSize( xDomain, xType, xProtocol, &uxSocketSize ) == pdFAIL ) + { + xReturn = FREERTOS_INVALID_SOCKET; + } + else + { + /* Allocate the structure that will hold the socket information. The + size depends on the type of socket: UDP sockets need less space. A + define 'pvPortMallocSocket' will used to allocate the necessary space. + By default it points to the FreeRTOS function 'pvPortMalloc()'. */ + pxSocket = ( FreeRTOS_Socket_t * ) pvPortMallocSocket( uxSocketSize ); + + if( pxSocket == NULL ) + { + pxSocket = ( FreeRTOS_Socket_t * ) FREERTOS_INVALID_SOCKET; + iptraceFAILED_TO_CREATE_SOCKET(); + } + else if( ( xEventGroup = xEventGroupCreate() ) == NULL ) + { + vPortFreeSocket( pxSocket ); + pxSocket = ( FreeRTOS_Socket_t * ) FREERTOS_INVALID_SOCKET; + iptraceFAILED_TO_CREATE_EVENT_GROUP(); + } + else + { + /* Clear the entire space to avoid nulling individual entries */ + memset( pxSocket, '\0', uxSocketSize ); + + pxSocket->xEventGroup = xEventGroup; + + /* Initialise the socket's members. The semaphore will be created + if the socket is bound to an address, for now the pointer to the + semaphore is just set to NULL to show it has not been created. */ + if( xProtocol == FREERTOS_IPPROTO_UDP ) + { + vListInitialise( &( pxSocket->u.xUDP.xWaitingPacketsList ) ); + + #if( ipconfigUDP_MAX_RX_PACKETS > 0 ) + { + pxSocket->u.xUDP.uxMaxPackets = ( UBaseType_t ) ipconfigUDP_MAX_RX_PACKETS; + } + #endif /* ipconfigUDP_MAX_RX_PACKETS > 0 */ + } + + vListInitialiseItem( &( pxSocket->xBoundSocketListItem ) ); + listSET_LIST_ITEM_OWNER( &( pxSocket->xBoundSocketListItem ), ( void * ) pxSocket ); + + pxSocket->xReceiveBlockTime = ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME; + pxSocket->xSendBlockTime = ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME; + pxSocket->ucSocketOptions = ( uint8_t ) FREERTOS_SO_UDPCKSUM_OUT; + pxSocket->ucProtocol = ( uint8_t ) xProtocol; /* protocol: UDP or TCP */ + + #if( ipconfigUSE_TCP == 1 ) + { + if( xProtocol == FREERTOS_IPPROTO_TCP ) + { + /* StreamSize is expressed in number of bytes */ + /* Round up buffer sizes to nearest multiple of MSS */ + pxSocket->u.xTCP.usInitMSS = pxSocket->u.xTCP.usCurMSS = ipconfigTCP_MSS; + pxSocket->u.xTCP.uxRxStreamSize = ( size_t ) ipconfigTCP_RX_BUFFER_LENGTH; + pxSocket->u.xTCP.uxTxStreamSize = ( size_t ) FreeRTOS_round_up( ipconfigTCP_TX_BUFFER_LENGTH, ipconfigTCP_MSS ); + /* Use half of the buffer size of the TCP windows */ + #if ( ipconfigUSE_TCP_WIN == 1 ) + { + pxSocket->u.xTCP.uxRxWinSize = FreeRTOS_max_uint32( 1UL, ( uint32_t ) ( pxSocket->u.xTCP.uxRxStreamSize / 2 ) / ipconfigTCP_MSS ); + pxSocket->u.xTCP.uxTxWinSize = FreeRTOS_max_uint32( 1UL, ( uint32_t ) ( pxSocket->u.xTCP.uxTxStreamSize / 2 ) / ipconfigTCP_MSS ); + } + #else + { + pxSocket->u.xTCP.uxRxWinSize = 1u; + pxSocket->u.xTCP.uxTxWinSize = 1u; + } + #endif + /* The above values are just defaults, and can be overridden by + calling FreeRTOS_setsockopt(). No buffers will be allocated until a + socket is connected and data is exchanged. */ + } + } + #endif /* ipconfigUSE_TCP == 1 */ + } + + xReturn = ( Socket_t ) pxSocket; + } + + /* Remove compiler warnings in the case the configASSERT() is not defined. */ + ( void ) xDomain; + + return xReturn; +} +/*-----------------------------------------------------------*/ + +#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) + + SocketSet_t FreeRTOS_CreateSocketSet( void ) + { + SocketSelect_t *pxSocketSet; + + pxSocketSet = ( SocketSelect_t * ) pvPortMalloc( sizeof( *pxSocketSet ) ); + + if( pxSocketSet != NULL ) + { + memset( pxSocketSet, '\0', sizeof( *pxSocketSet ) ); + pxSocketSet->xSelectGroup = xEventGroupCreate(); + + if( pxSocketSet->xSelectGroup == NULL ) + { + vPortFree( ( void* ) pxSocketSet ); + pxSocketSet = NULL; + } + } + + return ( SocketSet_t ) pxSocketSet; + } + +#endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) + + void FreeRTOS_DeleteSocketSet( SocketSet_t xSocketSet ) + { + SocketSelect_t *pxSocketSet = ( SocketSelect_t*) xSocketSet; + + vEventGroupDelete( pxSocketSet->xSelectGroup ); + vPortFree( ( void* ) pxSocketSet ); + } + +#endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) + + /* Add a socket to a set */ + void FreeRTOS_FD_SET( Socket_t xSocket, SocketSet_t xSocketSet, EventBits_t xSelectBits ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + SocketSelect_t *pxSocketSet = ( SocketSelect_t * ) xSocketSet; + + configASSERT( pxSocket != NULL ); + configASSERT( xSocketSet != NULL ); + + /* Make sure we're not adding bits which are reserved for internal use, + such as eSELECT_CALL_IP */ + pxSocket->xSelectBits |= ( xSelectBits & eSELECT_ALL ); + + if( ( pxSocket->xSelectBits & eSELECT_ALL ) != 0 ) + { + /* Adding a socket to a socket set. */ + pxSocket->pxSocketSet = ( SocketSelect_t * ) xSocketSet; + + /* Now have the IP-task call vSocketSelect() to see if the set contains + any sockets which are 'ready' and set the proper bits. + By setting 'bApiCalled = false', vSocketSelect() knows that it was + not called from a user API */ + pxSocketSet->bApiCalled = pdFALSE; + prvFindSelectedSocket( pxSocketSet ); + } + } + +#endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) + /* Clear select bits for a socket + If the mask becomes 0, remove the socket from the set */ + void FreeRTOS_FD_CLR( Socket_t xSocket, SocketSet_t xSocketSet, EventBits_t xSelectBits ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + + configASSERT( pxSocket != NULL ); + configASSERT( xSocketSet != NULL ); + + pxSocket->xSelectBits &= ~( xSelectBits & eSELECT_ALL ); + if( ( pxSocket->xSelectBits & eSELECT_ALL ) != 0 ) + { + pxSocket->pxSocketSet = ( SocketSelect_t *)xSocketSet; + } + else + { + /* disconnect it from the socket set */ + pxSocket->pxSocketSet = ( SocketSelect_t *)NULL; + } + } + +#endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */ +/*-----------------------------------------------------------*/ + + +#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) + + /* Test if a socket belongs to a socket-set */ + EventBits_t FreeRTOS_FD_ISSET( Socket_t xSocket, SocketSet_t xSocketSet ) + { + EventBits_t xReturn; + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + + configASSERT( pxSocket != NULL ); + configASSERT( xSocketSet != NULL ); + + if( xSocketSet == ( SocketSet_t ) pxSocket->pxSocketSet ) + { + /* Make sure we're not adding bits which are reserved for internal + use. */ + xReturn = pxSocket->xSocketBits & eSELECT_ALL; + } + else + { + xReturn = 0; + } + + return xReturn; + } + +#endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) + + /* The select() statement: wait for an event to occur on any of the sockets + included in a socket set */ + BaseType_t FreeRTOS_select( SocketSet_t xSocketSet, TickType_t xBlockTimeTicks ) + { + TimeOut_t xTimeOut; + TickType_t xRemainingTime; + SocketSelect_t *pxSocketSet = ( SocketSelect_t*) xSocketSet; + BaseType_t xResult; + + configASSERT( xSocketSet != NULL ); + + /* Only in the first round, check for non-blocking */ + xRemainingTime = xBlockTimeTicks; + + /* Fetch the current time */ + vTaskSetTimeOutState( &xTimeOut ); + + for( ;; ) + { + /* Find a socket which might have triggered the bit + This function might return immediately or block for a limited time */ + xResult = ( BaseType_t ) xEventGroupWaitBits( pxSocketSet->xSelectGroup, eSELECT_ALL, pdFALSE, pdFALSE, xRemainingTime ); + + #if( ipconfigSUPPORT_SIGNALS != 0 ) + { + if( ( xResult & eSELECT_INTR ) != 0u ) + { + xEventGroupClearBits( pxSocketSet->xSelectGroup, eSELECT_INTR ); + FreeRTOS_debug_printf( ( "FreeRTOS_select: interrupted\n" ) ); + break; + } + } + #endif /* ipconfigSUPPORT_SIGNALS */ + + /* Have the IP-task find the socket which had an event */ + pxSocketSet->bApiCalled = pdTRUE; + prvFindSelectedSocket( pxSocketSet ); + + xResult = ( BaseType_t ) xEventGroupGetBits( pxSocketSet->xSelectGroup ); + + if( xResult != 0 ) + { + break; + } + + /* Has the timeout been reached? */ + if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE ) + { + break; + } + } + + return xResult; + } + +#endif /* ipconfigSUPPORT_SELECT_FUNCTION */ +/*-----------------------------------------------------------*/ + +#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) + + /* Send a message to the IP-task to have it check all sockets belonging to + 'pxSocketSet' */ + static FreeRTOS_Socket_t *prvFindSelectedSocket( SocketSelect_t *pxSocketSet ) + { + IPStackEvent_t xSelectEvent; + FreeRTOS_Socket_t *xReturn; + + xSelectEvent.eEventType = eSocketSelectEvent; + xSelectEvent.pvData = ( void * ) pxSocketSet; + + /* while the IP-task works on the request, the API will block on + 'eSELECT_CALL_IP'. So clear it first. */ + xEventGroupClearBits( pxSocketSet->xSelectGroup, eSELECT_CALL_IP ); + + /* Now send the socket select event */ + if( xSendEventStructToIPTask( &xSelectEvent, ( TickType_t ) portMAX_DELAY ) == pdFAIL ) + { + /* Oops, we failed to wake-up the IP task. No use to wait for it. */ + FreeRTOS_debug_printf( ( "prvFindSelectedSocket: failed\n" ) ); + xReturn = NULL; + } + else + { + /* As soon as the IP-task is ready, it will set 'eSELECT_CALL_IP' to + wakeup the calling API */ + xEventGroupWaitBits( pxSocketSet->xSelectGroup, eSELECT_CALL_IP, pdTRUE, pdFALSE, portMAX_DELAY ); + + /* Return 'pxSocket' which is set by the IP-task */ + xReturn = pxSocketSet->pxSocket; + } + + return xReturn; + } + +#endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */ +/*-----------------------------------------------------------*/ + +/* + * FreeRTOS_recvfrom: receive data from a bound socket + * In this library, the function can only be used with connectionsless sockets + * (UDP) + */ +int32_t FreeRTOS_recvfrom( Socket_t xSocket, void *pvBuffer, size_t xBufferLength, BaseType_t xFlags, struct freertos_sockaddr *pxSourceAddress, socklen_t *pxSourceAddressLength ) +{ +BaseType_t lPacketCount = 0; +NetworkBufferDescriptor_t *pxNetworkBuffer; +FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; +TickType_t xRemainingTime = ( TickType_t ) 0; /* Obsolete assignment, but some compilers output a warning if its not done. */ +BaseType_t xTimed = pdFALSE; +TimeOut_t xTimeOut; +int32_t lReturn; +EventBits_t xEventBits = ( EventBits_t ) 0; + + if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_UDP, pdTRUE ) == pdFALSE ) + { + return -pdFREERTOS_ERRNO_EINVAL; + } + + lPacketCount = ( BaseType_t ) listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ); + + /* The function prototype is designed to maintain the expected Berkeley + sockets standard, but this implementation does not use all the parameters. */ + ( void ) pxSourceAddressLength; + + while( lPacketCount == 0 ) + { + if( xTimed == pdFALSE ) + { + /* Check to see if the socket is non blocking on the first + iteration. */ + xRemainingTime = pxSocket->xReceiveBlockTime; + + if( xRemainingTime == ( TickType_t ) 0 ) + { + #if( ipconfigSUPPORT_SIGNALS != 0 ) + { + /* Just check for the interrupt flag. */ + xEventBits = xEventGroupWaitBits( pxSocket->xEventGroup, eSOCKET_INTR, + pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, socketDONT_BLOCK ); + } + #endif /* ipconfigSUPPORT_SIGNALS */ + break; + } + + if( ( xFlags & FREERTOS_MSG_DONTWAIT ) != 0 ) + { + break; + } + + /* To ensure this part only executes once. */ + xTimed = pdTRUE; + + /* Fetch the current time. */ + vTaskSetTimeOutState( &xTimeOut ); + } + + /* Wait for arrival of data. While waiting, the IP-task may set the + 'eSOCKET_RECEIVE' bit in 'xEventGroup', if it receives data for this + socket, thus unblocking this API call. */ + xEventBits = xEventGroupWaitBits( pxSocket->xEventGroup, eSOCKET_RECEIVE | eSOCKET_INTR, + pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime ); + + #if( ipconfigSUPPORT_SIGNALS != 0 ) + { + if( ( xEventBits & eSOCKET_INTR ) != 0 ) + { + if( ( xEventBits & eSOCKET_RECEIVE ) != 0 ) + { + /* Shouldn't have cleared the eSOCKET_RECEIVE flag. */ + xEventGroupSetBits( pxSocket->xEventGroup, eSOCKET_RECEIVE ); + } + break; + } + } + #else + { + ( void ) xEventBits; + } + #endif /* ipconfigSUPPORT_SIGNALS */ + + lPacketCount = ( BaseType_t ) listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ); + + if( lPacketCount != 0 ) + { + break; + } + + /* Has the timeout been reached ? */ + if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) ) + { + break; + } + } /* while( lPacketCount == 0 ) */ + + if( lPacketCount != 0 ) + { + taskENTER_CRITICAL(); + { + /* The owner of the list item is the network buffer. */ + pxNetworkBuffer = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->u.xUDP.xWaitingPacketsList ) ); + + if( ( xFlags & FREERTOS_MSG_PEEK ) == 0 ) + { + /* Remove the network buffer from the list of buffers waiting to + be processed by the socket. */ + uxListRemove( &( pxNetworkBuffer->xBufferListItem ) ); + } + } + taskEXIT_CRITICAL(); + + /* The returned value is the length of the payload data, which is + calculated at the total packet size minus the headers. + The validity of `xDataLength` prvProcessIPPacket has been confirmed + in 'prvProcessIPPacket()'. */ + lReturn = ( int32_t ) ( pxNetworkBuffer->xDataLength - sizeof( UDPPacket_t ) ); + + if( pxSourceAddress != NULL ) + { + pxSourceAddress->sin_port = pxNetworkBuffer->usPort; + pxSourceAddress->sin_addr = pxNetworkBuffer->ulIPAddress; + } + + if( ( xFlags & FREERTOS_ZERO_COPY ) == 0 ) + { + /* The zero copy flag is not set. Truncate the length if it won't + fit in the provided buffer. */ + if( lReturn > ( int32_t ) xBufferLength ) + { + iptraceRECVFROM_DISCARDING_BYTES( ( xBufferLength - lReturn ) ); + lReturn = ( int32_t )xBufferLength; + } + + /* Copy the received data into the provided buffer, then release the + network buffer. */ + memcpy( pvBuffer, ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] ), ( size_t )lReturn ); + + if( ( xFlags & FREERTOS_MSG_PEEK ) == 0 ) + { + vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); + } + } + else + { + /* The zero copy flag was set. pvBuffer is not a buffer into which + the received data can be copied, but a pointer that must be set to + point to the buffer in which the received data has already been + placed. */ + *( ( void** ) pvBuffer ) = ( void * ) ( &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] ) ); + } + + } +#if( ipconfigSUPPORT_SIGNALS != 0 ) + else if( ( xEventBits & eSOCKET_INTR ) != 0 ) + { + lReturn = -pdFREERTOS_ERRNO_EINTR; + iptraceRECVFROM_INTERRUPTED(); + } +#endif /* ipconfigSUPPORT_SIGNALS */ + else + { + lReturn = -pdFREERTOS_ERRNO_EWOULDBLOCK; + iptraceRECVFROM_TIMEOUT(); + } + + return lReturn; +} +/*-----------------------------------------------------------*/ + +int32_t FreeRTOS_sendto( Socket_t xSocket, const void *pvBuffer, size_t xTotalDataLength, BaseType_t xFlags, const struct freertos_sockaddr *pxDestinationAddress, socklen_t xDestinationAddressLength ) +{ +NetworkBufferDescriptor_t *pxNetworkBuffer; +IPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL }; +TimeOut_t xTimeOut; +TickType_t xTicksToWait; +int32_t lReturn = 0; +FreeRTOS_Socket_t *pxSocket; + + pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + + /* The function prototype is designed to maintain the expected Berkeley + sockets standard, but this implementation does not use all the + parameters. */ + ( void ) xDestinationAddressLength; + configASSERT( pvBuffer ); + + if( xTotalDataLength <= ( size_t ) ipMAX_UDP_PAYLOAD_LENGTH ) + { + /* If the socket is not already bound to an address, bind it now. + Passing NULL as the address parameter tells FreeRTOS_bind() to select + the address to bind to. */ + if( ( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE ) || + ( FreeRTOS_bind( xSocket, NULL, 0u ) == 0 ) ) + { + xTicksToWait = pxSocket->xSendBlockTime; + + #if( ipconfigUSE_CALLBACKS != 0 ) + { + if( xIsCallingFromIPTask() != pdFALSE ) + { + /* If this send function is called from within a call-back + handler it may not block, otherwise chances would be big to + get a deadlock: the IP-task waiting for itself. */ + xTicksToWait = ( TickType_t )0; + } + } + #endif /* ipconfigUSE_CALLBACKS */ + + if( ( xFlags & FREERTOS_MSG_DONTWAIT ) != 0 ) + { + xTicksToWait = ( TickType_t ) 0; + } + + if( ( xFlags & FREERTOS_ZERO_COPY ) == 0 ) + { + /* Zero copy is not set, so obtain a network buffer into + which the payload will be copied. */ + vTaskSetTimeOutState( &xTimeOut ); + + /* Block until a buffer becomes available, or until a + timeout has been reached */ + pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( xTotalDataLength + sizeof( UDPPacket_t ), xTicksToWait ); + + if( pxNetworkBuffer != NULL ) + { + memcpy( ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] ), ( void * ) pvBuffer, xTotalDataLength ); + + if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdTRUE ) + { + /* The entire block time has been used up. */ + xTicksToWait = ( TickType_t ) 0; + } + } + } + else + { + /* When zero copy is used, pvBuffer is a pointer to the + payload of a buffer that has already been obtained from the + stack. Obtain the network buffer pointer from the buffer. */ + pxNetworkBuffer = pxUDPPayloadBuffer_to_NetworkBuffer( (void*)pvBuffer ); + } + + if( pxNetworkBuffer != NULL ) + { + /* xDataLength is the size of the total packet, including the Ethernet header. */ + pxNetworkBuffer->xDataLength = xTotalDataLength + sizeof( UDPPacket_t ); + pxNetworkBuffer->usPort = pxDestinationAddress->sin_port; + pxNetworkBuffer->usBoundPort = ( uint16_t ) socketGET_SOCKET_PORT( pxSocket ); + pxNetworkBuffer->ulIPAddress = pxDestinationAddress->sin_addr; + + /* The socket options are passed to the IP layer in the + space that will eventually get used by the Ethernet header. */ + pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] = pxSocket->ucSocketOptions; + + /* Tell the networking task that the packet needs sending. */ + xStackTxEvent.pvData = pxNetworkBuffer; + + /* Ask the IP-task to send this packet */ + if( xSendEventStructToIPTask( &xStackTxEvent, xTicksToWait ) == pdPASS ) + { + /* The packet was successfully sent to the IP task. */ + lReturn = ( int32_t ) xTotalDataLength; + #if( ipconfigUSE_CALLBACKS == 1 ) + { + if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xUDP.pxHandleSent ) ) + { + pxSocket->u.xUDP.pxHandleSent( ( Socket_t )pxSocket, xTotalDataLength ); + } + } + #endif /* ipconfigUSE_CALLBACKS */ + } + else + { + /* If the buffer was allocated in this function, release + it. */ + if( ( xFlags & FREERTOS_ZERO_COPY ) == 0 ) + { + vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); + } + iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT ); + } + } + else + { + /* If errno was available, errno would be set to + FREERTOS_ENOPKTS. As it is, the function must return the + number of transmitted bytes, so the calling function knows + how much data was actually sent. */ + iptraceNO_BUFFER_FOR_SENDTO(); + } + } + else + { + iptraceSENDTO_SOCKET_NOT_BOUND(); + } + } + else + { + /* The data is longer than the available buffer space. */ + iptraceSENDTO_DATA_TOO_LONG(); + } + + return lReturn; +} /* Tested */ +/*-----------------------------------------------------------*/ + +/* + * FreeRTOS_bind() : binds a sockt to a local port number. If port 0 is + * provided, a system provided port number will be assigned. This function can + * be used for both UDP and TCP sockets. The actual binding will be performed + * by the IP-task to avoid mutual access to the bound-socket-lists + * (xBoundUDPSocketsList or xBoundTCPSocketsList). + */ +BaseType_t FreeRTOS_bind( Socket_t xSocket, struct freertos_sockaddr * pxAddress, socklen_t xAddressLength ) +{ +IPStackEvent_t xBindEvent; +FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; +BaseType_t xReturn = 0; + + ( void ) xAddressLength; + + if( ( pxSocket == NULL ) || ( pxSocket == FREERTOS_INVALID_SOCKET ) ) + { + xReturn = -pdFREERTOS_ERRNO_EINVAL; + } + /* Once a socket is bound to a port, it can not be bound to a different + port number */ + else if( socketSOCKET_IS_BOUND( pxSocket) != pdFALSE ) + { + /* The socket is already bound. */ + FreeRTOS_debug_printf( ( "vSocketBind: Socket already bound to %d\n", pxSocket->usLocalPort ) ); + xReturn = -pdFREERTOS_ERRNO_EINVAL; + } + else + { + /* Prepare a messages to the IP-task in order to perform the binding. + The desired port number will be passed in usLocalPort. */ + xBindEvent.eEventType = eSocketBindEvent; + xBindEvent.pvData = ( void * ) xSocket; + if( pxAddress != NULL ) + { + pxSocket->usLocalPort = FreeRTOS_ntohs( pxAddress->sin_port ); + } + else + { + /* Caller wants to bind to a random port number. */ + pxSocket->usLocalPort = 0u; + } + + /* portMAX_DELAY is used as a the time-out parameter, as binding *must* + succeed before the socket can be used. _RB_ The use of an infinite + block time needs be changed as it could result in the task hanging. */ + if( xSendEventStructToIPTask( &xBindEvent, ( TickType_t ) portMAX_DELAY ) == pdFAIL ) + { + /* Failed to wake-up the IP-task, no use to wait for it */ + FreeRTOS_debug_printf( ( "FreeRTOS_bind: send event failed\n" ) ); + xReturn = -pdFREERTOS_ERRNO_ECANCELED; + } + else + { + /* The IP-task will set the 'eSOCKET_BOUND' bit when it has done its + job. */ + xEventGroupWaitBits( pxSocket->xEventGroup, eSOCKET_BOUND, pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, portMAX_DELAY ); + if( socketSOCKET_IS_BOUND( pxSocket ) == pdFALSE ) + { + xReturn = -pdFREERTOS_ERRNO_EINVAL; + } + } + } + + return xReturn; +} + +/* + * vSocketBind(): internal version of bind() that should not be called directly. + * 'xInternal' is used for TCP sockets only: it allows to have several + * (connected) child sockets bound to the same server port. + */ +BaseType_t vSocketBind( FreeRTOS_Socket_t *pxSocket, struct freertos_sockaddr * pxAddress, size_t uxAddressLength, BaseType_t xInternal ) +{ +BaseType_t xReturn = 0; /* In Berkeley sockets, 0 means pass for bind(). */ +List_t *pxSocketList; +#if( ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 ) + struct freertos_sockaddr xAddress; +#endif /* ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND */ + +#if( ipconfigUSE_TCP == 1 ) + if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + pxSocketList = &xBoundTCPSocketsList; + } + else +#endif /* ipconfigUSE_TCP == 1 */ + { + pxSocketList = &xBoundUDPSocketsList; + } + + /* The function prototype is designed to maintain the expected Berkeley + sockets standard, but this implementation does not use all the parameters. */ + ( void ) uxAddressLength; + + configASSERT( pxSocket ); + configASSERT( pxSocket != FREERTOS_INVALID_SOCKET ); + + #if( ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 ) + { + /* pxAddress will be NULL if sendto() was called on a socket without the + socket being bound to an address. In this case, automatically allocate + an address and port to the socket. */ + if( pxAddress == NULL ) + { + pxAddress = &xAddress; + /* Put the port to zero to be assigned later. */ + pxAddress->sin_port = 0u; + } + } + #endif /* ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 */ + + /* Sockets must be bound before calling FreeRTOS_sendto() if + ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is not set to 1. */ + configASSERT( pxAddress ); + + if( pxAddress != NULL ) + { + if( pxAddress->sin_port == 0u ) + { + pxAddress->sin_port = prvGetPrivatePortNumber( ( BaseType_t )pxSocket->ucProtocol ); + if( 0 == pxAddress->sin_port ) + { + return -pdFREERTOS_ERRNO_EADDRNOTAVAIL; + } + } + + /* If vSocketBind() is called from the API FreeRTOS_bind() it has been + confirmed that the socket was not yet bound to a port. If it is called + from the IP-task, no such check is necessary. */ + + /* Check to ensure the port is not already in use. If the bind is + called internally, a port MAY be used by more than one socket. */ + if( ( ( xInternal == pdFALSE ) || ( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) ) && + ( pxListFindListItemWithValue( pxSocketList, ( TickType_t ) pxAddress->sin_port ) != NULL ) ) + { + FreeRTOS_debug_printf( ( "vSocketBind: %sP port %d in use\n", + pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP ? "TC" : "UD", + FreeRTOS_ntohs( pxAddress->sin_port ) ) ); + xReturn = -pdFREERTOS_ERRNO_EADDRINUSE; + } + else + { + /* Allocate the port number to the socket. + This macro will set 'xBoundSocketListItem->xItemValue' */ + socketSET_SOCKET_PORT( pxSocket, pxAddress->sin_port ); + + /* And also store it in a socket field 'usLocalPort' in host-byte-order, + mostly used for logging and debugging purposes */ + pxSocket->usLocalPort = FreeRTOS_ntohs( pxAddress->sin_port ); + + /* Add the socket to the list of bound ports. */ + { + /* If the network driver can iterate through 'xBoundUDPSocketsList', + by calling xPortHasUDPSocket() then the IP-task must temporarily + suspend the scheduler to keep the list in a consistent state. */ + #if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 ) + { + vTaskSuspendAll(); + } + #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */ + + /* Add the socket to 'xBoundUDPSocketsList' or 'xBoundTCPSocketsList' */ + vListInsertEnd( pxSocketList, &( pxSocket->xBoundSocketListItem ) ); + + #if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 ) + { + xTaskResumeAll(); + } + #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */ + } + } + } + else + { + xReturn = -pdFREERTOS_ERRNO_EADDRNOTAVAIL; + FreeRTOS_debug_printf( ( "vSocketBind: Socket no addr\n" ) ); + } + + if( xReturn != 0 ) + { + iptraceBIND_FAILED( xSocket, ( FreeRTOS_ntohs( pxAddress->sin_port ) ) ); + } + + return xReturn; +} /* Tested */ +/*-----------------------------------------------------------*/ + +/* + * Close a socket and free the allocated space + * In case of a TCP socket: the connection will not be closed automatically + * Subsequent messages for the closed socket will be responded to with a RST + * The IP-task will actually close the socket, after receiving a 'eSocketCloseEvent' message + */ +BaseType_t FreeRTOS_closesocket( Socket_t xSocket ) +{ +BaseType_t xResult; +#if( ipconfigUSE_TCP == 1 ) && ( ipconfigUSE_CALLBACKS == 1 ) + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * )xSocket; +#endif +IPStackEvent_t xCloseEvent; +xCloseEvent.eEventType = eSocketCloseEvent; +xCloseEvent.pvData = ( void * ) xSocket; + + if( ( xSocket == NULL ) || ( xSocket == FREERTOS_INVALID_SOCKET ) ) + { + xResult = 0; + } + else + { + #if( ( ipconfigUSE_TCP == 1 ) && ( ipconfigUSE_CALLBACKS == 1 ) ) + { + if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + /* Make sure that IP-task won't call the user callback's anymore */ + pxSocket->u.xTCP.pxHandleConnected = NULL; + pxSocket->u.xTCP.pxHandleReceive = NULL; + pxSocket->u.xTCP.pxHandleSent = NULL; + } + } + #endif /* ( ( ipconfigUSE_TCP == 1 ) && ( ipconfigUSE_CALLBACKS == 1 ) ) */ + + /* Let the IP task close the socket to keep it synchronised with the + packet handling. */ + + /* Note when changing the time-out value below, it must be checked who is calling + this function. If it is called by the IP-task, a deadlock could occur. + The IP-task would only call it in case of a user call-back */ + if( xSendEventStructToIPTask( &xCloseEvent, ( TickType_t ) 0 ) == pdFAIL ) + { + FreeRTOS_debug_printf( ( "FreeRTOS_closesocket: failed\n" ) ); + xResult = -1; + } + else + { + xResult = 1; + } + } + + return xResult; +} + +/* This is the internal version of FreeRTOS_closesocket() + * It will be called by the IPtask only to avoid problems with synchronicity + */ +void *vSocketClose( FreeRTOS_Socket_t *pxSocket ) +{ +NetworkBufferDescriptor_t *pxNetworkBuffer; + + #if( ipconfigUSE_TCP == 1 ) + { + /* For TCP: clean up a little more. */ + if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + #if( ipconfigUSE_TCP_WIN == 1 ) + { + if( pxSocket->u.xTCP.pxAckMessage != NULL ) + { + vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage ); + } + /* Free the resources which were claimed by the tcpWin member */ + vTCPWindowDestroy( &pxSocket->u.xTCP.xTCPWindow ); + } + #endif /* ipconfigUSE_TCP_WIN */ + + /* Free the input and output streams */ + if( pxSocket->u.xTCP.rxStream != NULL ) + { + vPortFreeLarge( pxSocket->u.xTCP.rxStream ); + } + + if( pxSocket->u.xTCP.txStream != NULL ) + { + vPortFreeLarge( pxSocket->u.xTCP.txStream ); + } + + /* In case this is a child socket, make sure the child-count of the + parent socket is decreased. */ + prvTCPSetSocketCount( pxSocket ); + } + } + #endif /* ipconfigUSE_TCP == 1 */ + + /* Socket must be unbound first, to ensure no more packets are queued on + it. */ + if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE ) + { + /* If the network driver can iterate through 'xBoundUDPSocketsList', + by calling xPortHasUDPSocket(), then the IP-task must temporarily + suspend the scheduler to keep the list in a consistent state. */ + #if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 ) + { + vTaskSuspendAll(); + } + #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */ + + uxListRemove( &( pxSocket->xBoundSocketListItem ) ); + + #if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 ) + { + xTaskResumeAll(); + } + #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */ + } + + /* Now the socket is not bound the list of waiting packets can be + drained. */ + if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_UDP ) + { + while( listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ) > 0U ) + { + pxNetworkBuffer = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->u.xUDP.xWaitingPacketsList ) ); + uxListRemove( &( pxNetworkBuffer->xBufferListItem ) ); + vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); + } + } + + if( pxSocket->xEventGroup ) + { + vEventGroupDelete( pxSocket->xEventGroup ); + } + + #if( ipconfigUSE_TCP == 1 ) && ( ipconfigHAS_DEBUG_PRINTF != 0 ) + { + if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + FreeRTOS_debug_printf( ( "FreeRTOS_closesocket[%u to %lxip:%u]: buffers %lu socks %lu\n", + pxSocket->usLocalPort, + pxSocket->u.xTCP.ulRemoteIP, + pxSocket->u.xTCP.usRemotePort, + uxGetNumberOfFreeNetworkBuffers(), + listCURRENT_LIST_LENGTH( &xBoundTCPSocketsList ) ) ); + } + } + #endif /* ( ipconfigUSE_TCP == 1 ) && ( ipconfigHAS_DEBUG_PRINTF != 0 ) */ + + /* Anf finally, after all resources have been freed, free the socket space */ + vPortFreeSocket( pxSocket ); + + return 0; +} /* Tested */ + +/*-----------------------------------------------------------*/ + +#if ipconfigUSE_TCP == 1 + + /* + * When a child socket gets closed, make sure to update the child-count of the + * parent. When a listening parent socket is closed, make sure no child-sockets + * keep a pointer to it. + */ + static void prvTCPSetSocketCount( FreeRTOS_Socket_t *pxSocketToDelete ) + { + const ListItem_t *pxIterator; + const MiniListItem_t *pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( &xBoundTCPSocketsList ); + FreeRTOS_Socket_t *pxOtherSocket; + uint16_t usLocalPort = pxSocketToDelete->usLocalPort; + + for( pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd ); + pxIterator != ( const ListItem_t * ) pxEnd; + pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) ) + { + pxOtherSocket = ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator ); + if( ( pxOtherSocket->u.xTCP.ucTCPState == eTCP_LISTEN ) && + ( pxOtherSocket->usLocalPort == usLocalPort ) && + ( pxOtherSocket->u.xTCP.usChildCount ) ) + { + pxOtherSocket->u.xTCP.usChildCount--; + FreeRTOS_debug_printf( ( "Lost: Socket %u now has %u / %u child%s\n", + pxOtherSocket->usLocalPort, + pxOtherSocket->u.xTCP.usChildCount, + pxOtherSocket->u.xTCP.usBacklog, + pxOtherSocket->u.xTCP.usChildCount == 1u ? "" : "ren" ) ); + break; + } + } + } + +#endif /* ipconfigUSE_TCP == 1 */ + +/*-----------------------------------------------------------*/ + +BaseType_t FreeRTOS_setsockopt( Socket_t xSocket, int32_t lLevel, int32_t lOptionName, const void *pvOptionValue, size_t xOptionLength ) +{ +/* The standard Berkeley function returns 0 for success. */ +BaseType_t xReturn = -pdFREERTOS_ERRNO_EINVAL; +BaseType_t lOptionValue; +FreeRTOS_Socket_t *pxSocket; + + pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + + /* The function prototype is designed to maintain the expected Berkeley + sockets standard, but this implementation does not use all the parameters. */ + ( void ) lLevel; + ( void ) xOptionLength; + + configASSERT( xSocket ); + + switch( lOptionName ) + { + case FREERTOS_SO_RCVTIMEO : + /* Receive time out. */ + pxSocket->xReceiveBlockTime = *( ( TickType_t * ) pvOptionValue ); + xReturn = 0; + break; + + case FREERTOS_SO_SNDTIMEO : + pxSocket->xSendBlockTime = *( ( TickType_t * ) pvOptionValue ); + if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_UDP ) + { + /* The send time out is capped for the reason stated in the + comments where ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS is defined + in FreeRTOSIPConfig.h (assuming an official configuration file + is being used. */ + if( pxSocket->xSendBlockTime > ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS ) + { + pxSocket->xSendBlockTime = ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS; + } + } + else + { + /* For TCP socket, it isn't necessary to limit the blocking time + because the FreeRTOS_send() function does not wait for a network + buffer to become available. */ + } + xReturn = 0; + break; + #if( ipconfigUDP_MAX_RX_PACKETS > 0 ) + case FREERTOS_SO_UDP_MAX_RX_PACKETS: + if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_UDP ) + { + break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + } + pxSocket->u.xUDP.uxMaxPackets = *( ( UBaseType_t * ) pvOptionValue ); + xReturn = 0; + break; + #endif /* ipconfigUDP_MAX_RX_PACKETS */ + + case FREERTOS_SO_UDPCKSUM_OUT : + /* Turn calculating of the UDP checksum on/off for this socket. */ + lOptionValue = ( BaseType_t ) pvOptionValue; + + if( lOptionValue == 0 ) + { + pxSocket->ucSocketOptions &= ( uint8_t ) ~FREERTOS_SO_UDPCKSUM_OUT; + } + else + { + pxSocket->ucSocketOptions |= ( uint8_t ) FREERTOS_SO_UDPCKSUM_OUT; + } + xReturn = 0; + break; + + #if( ipconfigUSE_CALLBACKS == 1 ) + #if( ipconfigUSE_TCP == 1 ) + case FREERTOS_SO_TCP_CONN_HANDLER: /* Set a callback for (dis)connection events */ + case FREERTOS_SO_TCP_RECV_HANDLER: /* Install a callback for receiving TCP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */ + case FREERTOS_SO_TCP_SENT_HANDLER: /* Install a callback for sending TCP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */ + #endif /* ipconfigUSE_TCP */ + case FREERTOS_SO_UDP_RECV_HANDLER: /* Install a callback for receiving UDP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */ + case FREERTOS_SO_UDP_SENT_HANDLER: /* Install a callback for sending UDP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */ + { + #if( ipconfigUSE_TCP == 1 ) + { + UBaseType_t uxProtocol; + if( ( lOptionName == FREERTOS_SO_UDP_RECV_HANDLER ) || + ( lOptionName == FREERTOS_SO_UDP_SENT_HANDLER ) ) + { + uxProtocol = ( UBaseType_t ) FREERTOS_IPPROTO_UDP; + } + else + { + uxProtocol = ( UBaseType_t ) FREERTOS_IPPROTO_TCP; + } + + if( pxSocket->ucProtocol != ( uint8_t ) uxProtocol ) + { + break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + } + } + #else + { + /* No need to check if the socket has the right + protocol, because only UDP socket can be created. */ + } + #endif /* ipconfigUSE_TCP */ + + switch( lOptionName ) + { + #if ipconfigUSE_TCP == 1 + case FREERTOS_SO_TCP_CONN_HANDLER: + pxSocket->u.xTCP.pxHandleConnected = ((F_TCP_UDP_Handler_t *)pvOptionValue)->pxOnTCPConnected; + break; + case FREERTOS_SO_TCP_RECV_HANDLER: + pxSocket->u.xTCP.pxHandleReceive = ((F_TCP_UDP_Handler_t *)pvOptionValue)->pxOnTCPReceive; + break; + case FREERTOS_SO_TCP_SENT_HANDLER: + pxSocket->u.xTCP.pxHandleSent = ((F_TCP_UDP_Handler_t *)pvOptionValue)->pxOnTCPSent; + break; + #endif /* ipconfigUSE_TCP */ + case FREERTOS_SO_UDP_RECV_HANDLER: + pxSocket->u.xUDP.pxHandleReceive = ((F_TCP_UDP_Handler_t *)pvOptionValue)->pxOnUDPReceive; + break; + case FREERTOS_SO_UDP_SENT_HANDLER: + pxSocket->u.xUDP.pxHandleSent = ((F_TCP_UDP_Handler_t *)pvOptionValue)->pxOnUDPSent; + break; + default: + break; + } + } + + xReturn = 0; + break; + #endif /* ipconfigUSE_CALLBACKS */ + + #if( ipconfigUSE_TCP != 0 ) + #if( ipconfigSOCKET_HAS_USER_SEMAPHORE != 0 ) + /* Each socket has a semaphore on which the using task normally + sleeps. */ + case FREERTOS_SO_SET_SEMAPHORE: + { + pxSocket->pxUserSemaphore = *( ( SemaphoreHandle_t * ) pvOptionValue ); + xReturn = 0; + } + break; + #endif /* ipconfigSOCKET_HAS_USER_SEMAPHORE */ + + #if( ipconfigSOCKET_HAS_USER_WAKE_CALLBACK != 0 ) + case FREERTOS_SO_WAKEUP_CALLBACK: + { + /* Each socket can have a callback function that is executed + when there is an event the socket's owner might want to + process. */ + pxSocket->pxUserWakeCallback = ( SocketWakeupCallback_t ) pvOptionValue; + xReturn = 0; + } + break; + #endif /* ipconfigSOCKET_HAS_USER_WAKE_CALLBACK */ + + case FREERTOS_SO_SET_LOW_HIGH_WATER: + { + LowHighWater_t *pxLowHighWater = ( LowHighWater_t * ) pvOptionValue; + + if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + /* It is not allowed to access 'pxSocket->u.xTCP'. */ + FreeRTOS_debug_printf( ( "FREERTOS_SO_SET_LOW_HIGH_WATER: wrong socket type\n" ) ); + break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + } + if( ( pxLowHighWater->uxLittleSpace >= pxLowHighWater->uxEnoughSpace ) || + ( pxLowHighWater->uxEnoughSpace > pxSocket->u.xTCP.uxRxStreamSize ) ) + { + /* Impossible values. */ + FreeRTOS_debug_printf( ( "FREERTOS_SO_SET_LOW_HIGH_WATER: bad values\n" ) ); + break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + } + /* Send a STOP when buffer space drops below 'uxLittleSpace' bytes. */ + pxSocket->u.xTCP.uxLittleSpace = pxLowHighWater->uxLittleSpace; + /* Send a GO when buffer space grows above 'uxEnoughSpace' bytes. */ + pxSocket->u.xTCP.uxEnoughSpace = pxLowHighWater->uxEnoughSpace; + xReturn = 0; + } + break; + + case FREERTOS_SO_SNDBUF: /* Set the size of the send buffer, in units of MSS (TCP only) */ + case FREERTOS_SO_RCVBUF: /* Set the size of the receive buffer, in units of MSS (TCP only) */ + { + uint32_t ulNewValue; + + if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + FreeRTOS_debug_printf( ( "Set SO_%sBUF: wrong socket type\n", + ( lOptionName == FREERTOS_SO_SNDBUF ) ? "SND" : "RCV" ) ); + break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + } + + if( ( ( lOptionName == FREERTOS_SO_SNDBUF ) && ( pxSocket->u.xTCP.txStream != NULL ) ) || + ( ( lOptionName == FREERTOS_SO_RCVBUF ) && ( pxSocket->u.xTCP.rxStream != NULL ) ) ) + { + FreeRTOS_debug_printf( ( "Set SO_%sBUF: buffer already created\n", + ( lOptionName == FREERTOS_SO_SNDBUF ) ? "SND" : "RCV" ) ); + break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + } + + ulNewValue = *( ( uint32_t * ) pvOptionValue ); + + if( lOptionName == FREERTOS_SO_SNDBUF ) + { + /* Round up to nearest MSS size */ + ulNewValue = FreeRTOS_round_up( ulNewValue, ( uint32_t ) pxSocket->u.xTCP.usInitMSS ); + pxSocket->u.xTCP.uxTxStreamSize = ulNewValue; + } + else + { + pxSocket->u.xTCP.uxRxStreamSize = ulNewValue; + } + } + xReturn = 0; + break; + + case FREERTOS_SO_WIN_PROPERTIES: /* Set all buffer and window properties in one call, parameter is pointer to WinProperties_t */ + { + WinProperties_t* pxProps; + + if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + FreeRTOS_debug_printf( ( "Set SO_WIN_PROP: wrong socket type\n" ) ); + break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + } + + if( ( pxSocket->u.xTCP.txStream != NULL ) || ( pxSocket->u.xTCP.rxStream != NULL ) ) + { + FreeRTOS_debug_printf( ( "Set SO_WIN_PROP: buffer already created\n" ) ); + break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + } + + pxProps = ( ( WinProperties_t * ) pvOptionValue ); + + if ( FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDBUF, &( pxProps->lTxBufSize ), sizeof( pxProps->lTxBufSize ) ) != 0 ) + { + break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + } + + if ( FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVBUF, &( pxProps->lRxBufSize ), sizeof( pxProps->lRxBufSize ) ) != 0 ) + { + break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + } + + #if( ipconfigUSE_TCP_WIN == 1 ) + { + pxSocket->u.xTCP.uxRxWinSize = ( uint32_t )pxProps->lRxWinSize; /* Fixed value: size of the TCP reception window */ + pxSocket->u.xTCP.uxTxWinSize = ( uint32_t )pxProps->lTxWinSize; /* Fixed value: size of the TCP transmit window */ + } + #else + { + pxSocket->u.xTCP.uxRxWinSize = 1u; + pxSocket->u.xTCP.uxTxWinSize = 1u; + } + #endif + + /* In case the socket has already initialised its tcpWin, + adapt the window size parameters */ + if( pxSocket->u.xTCP.xTCPWindow.u.bits.bHasInit != pdFALSE_UNSIGNED ) + { + pxSocket->u.xTCP.xTCPWindow.xSize.ulRxWindowLength = pxSocket->u.xTCP.uxRxWinSize * pxSocket->u.xTCP.usInitMSS; + pxSocket->u.xTCP.xTCPWindow.xSize.ulTxWindowLength = pxSocket->u.xTCP.uxTxWinSize * pxSocket->u.xTCP.usInitMSS; + } + } + + xReturn = 0; + break; + + case FREERTOS_SO_REUSE_LISTEN_SOCKET: /* If true, the server-socket will turn into a connected socket */ + { + if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + } + if( *( ( BaseType_t * ) pvOptionValue ) != 0 ) + { + pxSocket->u.xTCP.bits.bReuseSocket = pdTRUE_UNSIGNED; + } + else + { + pxSocket->u.xTCP.bits.bReuseSocket = pdFALSE_UNSIGNED; + } + } + xReturn = 0; + break; + + case FREERTOS_SO_CLOSE_AFTER_SEND: /* As soon as the last byte has been transmitted, finalise the connection */ + { + if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + } + + if( *( ( BaseType_t * ) pvOptionValue ) != 0 ) + { + pxSocket->u.xTCP.bits.bCloseAfterSend = pdTRUE_UNSIGNED; + } + else + { + pxSocket->u.xTCP.bits.bCloseAfterSend = pdFALSE_UNSIGNED; + } + } + xReturn = 0; + break; + + case FREERTOS_SO_SET_FULL_SIZE: /* Refuse to send packets smaller than MSS */ + { + if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + } + + if( *( ( BaseType_t * ) pvOptionValue ) != 0 ) + { + pxSocket->u.xTCP.xTCPWindow.u.bits.bSendFullSize = pdTRUE_UNSIGNED; + } + else + { + pxSocket->u.xTCP.xTCPWindow.u.bits.bSendFullSize = pdFALSE_UNSIGNED; + } + + if( ( pxSocket->u.xTCP.xTCPWindow.u.bits.bSendFullSize == pdFALSE_UNSIGNED ) && + ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) && + ( FreeRTOS_outstanding( pxSocket ) != 0 ) ) + { + pxSocket->u.xTCP.usTimeout = 1u; /* to set/clear bSendFullSize */ + xSendEventToIPTask( eTCPTimerEvent ); + } + } + xReturn = 0; + break; + + case FREERTOS_SO_STOP_RX: /* Refuse to receive more packts */ + { + if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + } + + if( *( ( BaseType_t * ) pvOptionValue ) != 0 ) + { + pxSocket->u.xTCP.bits.bRxStopped = pdTRUE_UNSIGNED; + } + else + { + pxSocket->u.xTCP.bits.bRxStopped = pdFALSE_UNSIGNED; + } + + pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED; + pxSocket->u.xTCP.usTimeout = 1u; /* to set/clear bRxStopped */ + xSendEventToIPTask( eTCPTimerEvent ); + } + xReturn = 0; + break; + + #endif /* ipconfigUSE_TCP == 1 */ + + default : + /* No other options are handled. */ + xReturn = -pdFREERTOS_ERRNO_ENOPROTOOPT; + break; + } + + return xReturn; +} /* Tested */ + +/*-----------------------------------------------------------*/ + +/* Find an available port number per https://tools.ietf.org/html/rfc6056. */ +static uint16_t prvGetPrivatePortNumber( BaseType_t xProtocol ) +{ +const uint16_t usEphemeralPortCount = + socketAUTO_PORT_ALLOCATION_MAX_NUMBER - socketAUTO_PORT_ALLOCATION_START_NUMBER + 1; +uint16_t usIterations = usEphemeralPortCount; +uint32_t ulRandomSeed = 0; +uint16_t usResult = 0; +const List_t *pxList; + +#if ipconfigUSE_TCP == 1 + if( xProtocol == ( BaseType_t ) FREERTOS_IPPROTO_TCP ) + { + pxList = &xBoundTCPSocketsList; + } + else +#endif + { + pxList = &xBoundUDPSocketsList; + } + + /* Avoid compiler warnings if ipconfigUSE_TCP is not defined. */ + ( void ) xProtocol; + + /* Find the next available port using the random seed as a starting + point. */ + do + { + /* Only proceed if the random number generator succeeded. */ + if( xApplicationGetRandomNumber( &( ulRandomSeed ) ) == pdFALSE ) + { + break; + } + + /* Map the random to a candidate port. */ + usResult = + socketAUTO_PORT_ALLOCATION_START_NUMBER + + ( ( ( uint16_t )ulRandomSeed ) % usEphemeralPortCount ); + + /* Check if there's already an open socket with the same protocol + and port. */ + if( NULL == pxListFindListItemWithValue( + pxList, + ( TickType_t )FreeRTOS_htons( usResult ) ) ) + { + usResult = FreeRTOS_htons( usResult ); + break; + } + else + { + usResult = 0; + } + + usIterations--; + } + while( usIterations > 0 ); + + return usResult; +} +/*-----------------------------------------------------------*/ + +/* pxListFindListItemWithValue: find a list item in a bound socket list +'xWantedItemValue' refers to a port number */ +static const ListItem_t * pxListFindListItemWithValue( const List_t *pxList, TickType_t xWantedItemValue ) +{ +const ListItem_t * pxResult = NULL; + + if( ( xIPIsNetworkTaskReady() != pdFALSE ) && ( pxList != NULL ) ) + { + const ListItem_t *pxIterator; + const MiniListItem_t *pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( pxList ); + for( pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd ); + pxIterator != ( const ListItem_t * ) pxEnd; + pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) ) + { + if( listGET_LIST_ITEM_VALUE( pxIterator ) == xWantedItemValue ) + { + pxResult = pxIterator; + break; + } + } + } + + return pxResult; +} /* Tested */ + +/*-----------------------------------------------------------*/ + +FreeRTOS_Socket_t *pxUDPSocketLookup( UBaseType_t uxLocalPort ) +{ +const ListItem_t *pxListItem; +FreeRTOS_Socket_t *pxSocket = NULL; + + /* Looking up a socket is quite simple, find a match with the local port. + + See if there is a list item associated with the port number on the + list of bound sockets. */ + pxListItem = pxListFindListItemWithValue( &xBoundUDPSocketsList, ( TickType_t ) uxLocalPort ); + + if( pxListItem != NULL ) + { + /* The owner of the list item is the socket itself. */ + pxSocket = ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxListItem ); + configASSERT( pxSocket != NULL ); + } + return pxSocket; +} + +/*-----------------------------------------------------------*/ + +#if ipconfigINCLUDE_FULL_INET_ADDR == 1 + + uint32_t FreeRTOS_inet_addr( const char * pcIPAddress ) + { + const uint32_t ulDecimalBase = 10u; + uint8_t ucOctet[ socketMAX_IP_ADDRESS_OCTETS ]; + const char *pcPointerOnEntering; + uint32_t ulReturn = 0UL, ulValue; + UBaseType_t uxOctetNumber; + BaseType_t xResult = pdPASS; + + for( uxOctetNumber = 0u; uxOctetNumber < socketMAX_IP_ADDRESS_OCTETS; uxOctetNumber++ ) + { + ulValue = 0ul; + pcPointerOnEntering = pcIPAddress; + + while( ( *pcIPAddress >= '0' ) && ( *pcIPAddress <= '9' ) ) + { + /* Move previous read characters into the next decimal + position. */ + ulValue *= ulDecimalBase; + + /* Add the binary value of the ascii character. */ + ulValue += ( ( uint32_t ) ( *pcIPAddress ) - ( uint32_t ) '0' ); + + /* Move to next character in the string. */ + pcIPAddress++; + } + + /* Check characters were read. */ + if( pcIPAddress == pcPointerOnEntering ) + { + xResult = pdFAIL; + } + + /* Check the value fits in an 8-bit number. */ + if( ulValue > 0xffUL ) + { + xResult = pdFAIL; + } + else + { + ucOctet[ uxOctetNumber ] = ( uint8_t ) ulValue; + + /* Check the next character is as expected. */ + if( uxOctetNumber < ( socketMAX_IP_ADDRESS_OCTETS - 1u ) ) + { + if( *pcIPAddress != '.' ) + { + xResult = pdFAIL; + } + else + { + /* Move past the dot. */ + pcIPAddress++; + } + } + } + + if( xResult == pdFAIL ) + { + /* No point going on. */ + break; + } + } + + if( *pcIPAddress != ( char ) 0 ) + { + /* Expected the end of the string. */ + xResult = pdFAIL; + } + + if( uxOctetNumber != socketMAX_IP_ADDRESS_OCTETS ) + { + /* Didn't read enough octets. */ + xResult = pdFAIL; + } + + if( xResult == pdPASS ) + { + ulReturn = FreeRTOS_inet_addr_quick( ucOctet[ 0 ], ucOctet[ 1 ], ucOctet[ 2 ], ucOctet[ 3 ] ); + } + + return ulReturn; + } + +#endif /* ipconfigINCLUDE_FULL_INET_ADDR */ + +/*-----------------------------------------------------------*/ + +/* Function to get the local address and IP port */ +size_t FreeRTOS_GetLocalAddress( Socket_t xSocket, struct freertos_sockaddr *pxAddress ) +{ +FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + + /* IP address of local machine. */ + pxAddress->sin_addr = *ipLOCAL_IP_ADDRESS_POINTER; + + /* Local port on this machine. */ + pxAddress->sin_port = FreeRTOS_htons( pxSocket->usLocalPort ); + + return sizeof( *pxAddress ); +} + +/*-----------------------------------------------------------*/ + +void vSocketWakeUpUser( FreeRTOS_Socket_t *pxSocket ) +{ +/* _HT_ must work this out, now vSocketWakeUpUser will be called for any important + * event or transition */ + #if( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 ) + { + if( pxSocket->pxUserSemaphore != NULL ) + { + xSemaphoreGive( pxSocket->pxUserSemaphore ); + } + } + #endif /* ipconfigSOCKET_HAS_USER_SEMAPHORE */ + + #if( ipconfigSOCKET_HAS_USER_WAKE_CALLBACK == 1 ) + { + if( pxSocket->pxUserWakeCallback != NULL ) + { + pxSocket->pxUserWakeCallback( pxSocket ); + } + } + #endif /* ipconfigSOCKET_HAS_USER_SEMAPHORE */ + + #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) + { + if( pxSocket->pxSocketSet != NULL ) + { + EventBits_t xSelectBits = ( pxSocket->xEventBits >> SOCKET_EVENT_BIT_COUNT ) & eSELECT_ALL; + if( xSelectBits != 0ul ) + { + pxSocket->xSocketBits |= xSelectBits; + xEventGroupSetBits( pxSocket->pxSocketSet->xSelectGroup, xSelectBits ); + } + } + + pxSocket->xEventBits &= eSOCKET_ALL; + } + #endif /* ipconfigSUPPORT_SELECT_FUNCTION */ + + if( ( pxSocket->xEventGroup != NULL ) && ( pxSocket->xEventBits != 0u ) ) + { + xEventGroupSetBits( pxSocket->xEventGroup, pxSocket->xEventBits ); + } + + pxSocket->xEventBits = 0ul; +} + +/*-----------------------------------------------------------*/ + +#if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 ) + + /* This define makes it possible for network-card drivers to inspect + * UDP message and see if there is any UDP socket bound to a given port + * number. + * This is probably only usefull in systems with a minimum of RAM and + * when lots of anonymous broadcast messages come in + */ + BaseType_t xPortHasUDPSocket( uint16_t usPortNr ) + { + BaseType_t xFound = pdFALSE; + + vTaskSuspendAll(); + { + if( ( pxListFindListItemWithValue( &xBoundUDPSocketsList, ( TickType_t ) usPortNr ) != NULL ) ) + { + xFound = pdTRUE; + } + } + xTaskResumeAll(); + + return xFound; + } + +#endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */ + +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + static BaseType_t bMayConnect( FreeRTOS_Socket_t *pxSocket ); + static BaseType_t bMayConnect( FreeRTOS_Socket_t *pxSocket ) + { + switch( pxSocket->u.xTCP.ucTCPState ) + { + case eCLOSED: + case eCLOSE_WAIT: return 0; + case eCONNECT_SYN: return -pdFREERTOS_ERRNO_EINPROGRESS; + default: return -pdFREERTOS_ERRNO_EAGAIN; + } + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + static BaseType_t prvTCPConnectStart( FreeRTOS_Socket_t *pxSocket, struct freertos_sockaddr *pxAddress ) + { + BaseType_t xResult = 0; + + if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdFALSE ) == pdFALSE ) + { + /* Not a valid socket or wrong type */ + xResult = -pdFREERTOS_ERRNO_EBADF; + } + else if( FreeRTOS_issocketconnected( pxSocket ) > 0 ) + { + /* The socket is already connected. */ + xResult = -pdFREERTOS_ERRNO_EISCONN; + } + else if( socketSOCKET_IS_BOUND( pxSocket ) == pdFALSE ) + { + /* Bind the socket to the port that the client task will send from. + Non-standard, so the error returned is that returned by bind(). */ + xResult = FreeRTOS_bind( ( Socket_t ) pxSocket, NULL, 0u ); + } + + if( xResult == 0 ) + { + /* Check if it makes any sense to wait for a connect event, this condition + might change while sleeping, so it must be checked within each loop */ + xResult = bMayConnect( pxSocket ); /* -EINPROGRESS, -EAGAIN, or 0 for OK */ + + /* Start the connect procedure, kernel will start working on it */ + if( xResult == 0 ) + { + pxSocket->u.xTCP.bits.bConnPrepared = pdFALSE_UNSIGNED; + pxSocket->u.xTCP.ucRepCount = 0u; + + FreeRTOS_debug_printf( ( "FreeRTOS_connect: %u to %lxip:%u\n", + pxSocket->usLocalPort, FreeRTOS_ntohl( pxAddress->sin_addr ), FreeRTOS_ntohs( pxAddress->sin_port ) ) ); + + /* Port on remote machine. */ + pxSocket->u.xTCP.usRemotePort = FreeRTOS_ntohs( pxAddress->sin_port ); + + /* IP address of remote machine. */ + pxSocket->u.xTCP.ulRemoteIP = FreeRTOS_ntohl( pxAddress->sin_addr ); + + /* (client) internal state: socket wants to send a connect. */ + vTCPStateChange( pxSocket, eCONNECT_SYN ); + + /* To start an active connect. */ + pxSocket->u.xTCP.usTimeout = 1u; + + if( xSendEventToIPTask( eTCPTimerEvent ) != pdPASS ) + { + xResult = -pdFREERTOS_ERRNO_ECANCELED; + } + } + } + + return xResult; + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + /* + * FreeRTOS_connect: socket wants to connect to a remote port + */ + BaseType_t FreeRTOS_connect( Socket_t xClientSocket, struct freertos_sockaddr *pxAddress, socklen_t xAddressLength ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t* ) xClientSocket; + TickType_t xRemainingTime; + BaseType_t xTimed = pdFALSE; + BaseType_t xResult; + TimeOut_t xTimeOut; + + ( void ) xAddressLength; + + xResult = prvTCPConnectStart( pxSocket, pxAddress ); + + if( xResult == 0 ) + { + /* And wait for the result */ + for( ;; ) + { + if( xTimed == pdFALSE ) + { + /* Only in the first round, check for non-blocking */ + xRemainingTime = pxSocket->xReceiveBlockTime; + if( xRemainingTime == ( TickType_t )0 ) + { + /* Not yet connected, correct state, non-blocking. */ + xResult = -pdFREERTOS_ERRNO_EWOULDBLOCK; + break; + } + + /* Don't get here a second time. */ + xTimed = pdTRUE; + + /* Fetch the current time */ + vTaskSetTimeOutState( &xTimeOut ); + } + + /* Did it get connected while sleeping ? */ + xResult = FreeRTOS_issocketconnected( pxSocket ); + + /* Returns positive when connected, negative means an error */ + if( xResult < 0 ) + { + /* Return the error */ + break; + } + + if( xResult > 0 ) + { + /* Socket now connected, return a zero */ + xResult = 0; + break; + } + + /* Is it allowed to sleep more? */ + if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) ) + { + xResult = -pdFREERTOS_ERRNO_ETIMEDOUT; + break; + } + + /* Go sleeping until we get any down-stream event */ + xEventGroupWaitBits( pxSocket->xEventGroup, eSOCKET_CONNECT, pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime ); + } + } + + return xResult; + } +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + /* + * FreeRTOS_accept: can return a new connected socket + * if the server socket is in listen mode and receives a connection request + * The new socket will be bound already to the same port number as the listing + * socket. + */ + Socket_t FreeRTOS_accept( Socket_t xServerSocket, struct freertos_sockaddr *pxAddress, socklen_t *pxAddressLength ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xServerSocket; + FreeRTOS_Socket_t *pxClientSocket = NULL; + TickType_t xRemainingTime; + BaseType_t xTimed = pdFALSE, xAsk = pdFALSE; + TimeOut_t xTimeOut; + IPStackEvent_t xAskEvent; + + if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE ) + { + /* Not a valid socket or wrong type */ + pxClientSocket = ( FreeRTOS_Socket_t * ) FREERTOS_INVALID_SOCKET; + } + else if( ( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED ) && + ( pxSocket->u.xTCP.ucTCPState != eTCP_LISTEN ) ) + { + /* Parent socket is not in listening mode */ + pxClientSocket = ( FreeRTOS_Socket_t * ) FREERTOS_INVALID_SOCKET; + } + else + { + /* Loop will stop with breaks. */ + for( ; ; ) + { + /* Is there a new client? */ + vTaskSuspendAll(); + { + if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED ) + { + pxClientSocket = pxSocket->u.xTCP.pxPeerSocket; + } + else + { + pxClientSocket = pxSocket; + } + if( pxClientSocket != NULL ) + { + pxSocket->u.xTCP.pxPeerSocket = NULL; + + /* Is it still not taken ? */ + if( pxClientSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) + { + pxClientSocket->u.xTCP.bits.bPassAccept = pdFALSE_UNSIGNED; + } + else + { + pxClientSocket = NULL; + } + } + } + xTaskResumeAll(); + + if( pxClientSocket != NULL ) + { + if( pxAddress != NULL ) + { + /* IP address of remote machine. */ + pxAddress->sin_addr = FreeRTOS_ntohl( pxClientSocket->u.xTCP.ulRemoteIP ); + + /* Port on remote machine. */ + pxAddress->sin_port = FreeRTOS_ntohs( pxClientSocket->u.xTCP.usRemotePort ); + } + if( pxAddressLength != NULL ) + { + *pxAddressLength = sizeof( *pxAddress ); + } + + if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED ) + { + xAsk = pdTRUE; + } + } + + if( xAsk != pdFALSE ) + { + /* Ask to set an event in 'xEventGroup' as soon as a new + client gets connected for this listening socket. */ + xAskEvent.eEventType = eTCPAcceptEvent; + xAskEvent.pvData = ( void * ) pxSocket; + xSendEventStructToIPTask( &xAskEvent, portMAX_DELAY ); + } + + if( pxClientSocket != NULL ) + { + break; + } + + if( xTimed == pdFALSE ) + { + /* Only in the first round, check for non-blocking */ + xRemainingTime = pxSocket->xReceiveBlockTime; + if( xRemainingTime == ( TickType_t ) 0 ) + { + break; + } + + /* Don't get here a second time */ + xTimed = pdTRUE; + + /* Fetch the current time */ + vTaskSetTimeOutState( &xTimeOut ); + } + + /* Has the timeout been reached? */ + if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE ) + { + break; + } + + /* Go sleeping until we get any down-stream event */ + xEventGroupWaitBits( pxSocket->xEventGroup, eSOCKET_ACCEPT, pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime ); + } + } + + return ( Socket_t ) pxClientSocket; + } +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + /* + * Read incoming data from a TCP socket + * Only after the last byte has been read, a close error might be returned + */ + BaseType_t FreeRTOS_recv( Socket_t xSocket, void *pvBuffer, size_t xBufferLength, BaseType_t xFlags ) + { + BaseType_t xByteCount; + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + TickType_t xRemainingTime; + BaseType_t xTimed = pdFALSE; + TimeOut_t xTimeOut; + EventBits_t xEventBits = ( EventBits_t ) 0; + + /* Check if the socket is valid, has type TCP and if it is bound to a + port. */ + if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE ) + { + xByteCount = -pdFREERTOS_ERRNO_EINVAL; + } + else + { + if( pxSocket->u.xTCP.rxStream != NULL ) + { + xByteCount = ( BaseType_t )uxStreamBufferGetSize ( pxSocket->u.xTCP.rxStream ); + } + else + { + xByteCount = 0; + } + + while( xByteCount == 0 ) + { + switch( pxSocket->u.xTCP.ucTCPState ) + { + case eCLOSED: + case eCLOSE_WAIT: /* (server + client) waiting for a connection termination request from the local user. */ + case eCLOSING: /* (server + client) waiting for a connection termination request acknowledgement from the remote TCP. */ + if( pxSocket->u.xTCP.bits.bMallocError != pdFALSE_UNSIGNED ) + { + /* The no-memory error has priority above the non-connected error. + Both are fatal and will elad to closing the socket. */ + xByteCount = -pdFREERTOS_ERRNO_ENOMEM; + } + else + { + xByteCount = -pdFREERTOS_ERRNO_ENOTCONN; + } + /* Call continue to break out of the switch and also the while + loop. */ + continue; + default: + break; + } + + if( xTimed == pdFALSE ) + { + /* Only in the first round, check for non-blocking. */ + xRemainingTime = pxSocket->xReceiveBlockTime; + + if( xRemainingTime == ( TickType_t ) 0 ) + { + #if( ipconfigSUPPORT_SIGNALS != 0 ) + { + /* Just check for the interrupt flag. */ + xEventBits = xEventGroupWaitBits( pxSocket->xEventGroup, eSOCKET_INTR, + pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, socketDONT_BLOCK ); + } + #endif /* ipconfigSUPPORT_SIGNALS */ + break; + } + + if( ( xFlags & FREERTOS_MSG_DONTWAIT ) != 0 ) + { + break; + } + + /* Don't get here a second time. */ + xTimed = pdTRUE; + + /* Fetch the current time. */ + vTaskSetTimeOutState( &xTimeOut ); + } + + /* Has the timeout been reached? */ + if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE ) + { + break; + } + + /* Block until there is a down-stream event. */ + xEventBits = xEventGroupWaitBits( pxSocket->xEventGroup, + eSOCKET_RECEIVE | eSOCKET_CLOSED | eSOCKET_INTR, + pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime ); + #if( ipconfigSUPPORT_SIGNALS != 0 ) + { + if( ( xEventBits & eSOCKET_INTR ) != 0u ) + { + break; + } + } + #else + { + ( void ) xEventBits; + } + #endif /* ipconfigSUPPORT_SIGNALS */ + + if( pxSocket->u.xTCP.rxStream != NULL ) + { + xByteCount = ( BaseType_t ) uxStreamBufferGetSize ( pxSocket->u.xTCP.rxStream ); + } + else + { + xByteCount = 0; + } + } + + #if( ipconfigSUPPORT_SIGNALS != 0 ) + if( ( xEventBits & eSOCKET_INTR ) != 0 ) + { + if( ( xEventBits & ( eSOCKET_RECEIVE | eSOCKET_CLOSED ) ) != 0 ) + { + /* Shouldn't have cleared other flags. */ + xEventBits &= ~eSOCKET_INTR; + xEventGroupSetBits( pxSocket->xEventGroup, xEventBits ); + } + xByteCount = -pdFREERTOS_ERRNO_EINTR; + } + else + #endif /* ipconfigSUPPORT_SIGNALS */ + if( xByteCount > 0 ) + { + if( ( xFlags & FREERTOS_ZERO_COPY ) == 0 ) + { + xByteCount = ( BaseType_t ) uxStreamBufferGet( pxSocket->u.xTCP.rxStream, 0ul, ( uint8_t * ) pvBuffer, ( size_t ) xBufferLength, ( xFlags & FREERTOS_MSG_PEEK ) != 0 ); + if( pxSocket->u.xTCP.bits.bLowWater != pdFALSE_UNSIGNED ) + { + /* We had reached the low-water mark, now see if the flag + can be cleared */ + size_t uxFrontSpace = uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream ); + + if( uxFrontSpace >= pxSocket->u.xTCP.uxEnoughSpace ) + { + pxSocket->u.xTCP.bits.bLowWater = pdFALSE_UNSIGNED; + pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED; + pxSocket->u.xTCP.usTimeout = 1u; /* because bLowWater is cleared. */ + xSendEventToIPTask( eTCPTimerEvent ); + } + } + } + else + { + /* Zero-copy reception of data: pvBuffer is a pointer to a pointer. */ + xByteCount = ( BaseType_t ) uxStreamBufferGetPtr( pxSocket->u.xTCP.rxStream, (uint8_t **)pvBuffer ); + } + } + } /* prvValidSocket() */ + + return xByteCount; + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + static int32_t prvTCPSendCheck( FreeRTOS_Socket_t *pxSocket, size_t xDataLength ) + { + int32_t xResult = 1; + + /* Is this a socket of type TCP and is it already bound to a port number ? */ + if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE ) + { + xResult = -pdFREERTOS_ERRNO_EINVAL; + } + else if( pxSocket->u.xTCP.bits.bMallocError != pdFALSE_UNSIGNED ) + { + xResult = -pdFREERTOS_ERRNO_ENOMEM; + } + else if( pxSocket->u.xTCP.ucTCPState == eCLOSED || + pxSocket->u.xTCP.ucTCPState == eCLOSE_WAIT || + pxSocket->u.xTCP.ucTCPState == eCLOSING ) + { + xResult = -pdFREERTOS_ERRNO_ENOTCONN; + } + else if( pxSocket->u.xTCP.bits.bFinSent != pdFALSE_UNSIGNED ) + { + /* This TCP connection is closing already, the FIN flag has been sent. + Maybe it is still delivering or receiving data. + Return OK in order not to get closed/deleted too quickly */ + xResult = 0; + } + else if( xDataLength == 0ul ) + { + /* send() is being called to send zero bytes */ + xResult = 0; + } + else if( pxSocket->u.xTCP.txStream == NULL ) + { + /* Create the outgoing stream only when it is needed */ + prvTCPCreateStream( pxSocket, pdFALSE ); + + if( pxSocket->u.xTCP.txStream == NULL ) + { + xResult = -pdFREERTOS_ERRNO_ENOMEM; + } + } + + return xResult; + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + /* Get a direct pointer to the circular transmit buffer. + '*pxLength' will contain the number of bytes that may be written. */ + uint8_t *FreeRTOS_get_tx_head( Socket_t xSocket, BaseType_t *pxLength ) + { + uint8_t *pucReturn = NULL; + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + StreamBuffer_t *pxBuffer = NULL; + + *pxLength = 0; + + /* Confirm that this is a TCP socket before dereferencing structure + member pointers. */ + if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdFALSE ) == pdTRUE ) + { + pxBuffer = pxSocket->u.xTCP.txStream; + if( pxBuffer != NULL ) + { + BaseType_t xSpace = ( BaseType_t )uxStreamBufferGetSpace( pxBuffer ); + BaseType_t xRemain = ( BaseType_t )( pxBuffer->LENGTH - pxBuffer->uxHead ); + + *pxLength = FreeRTOS_min_BaseType( xSpace, xRemain ); + pucReturn = pxBuffer->ucArray + pxBuffer->uxHead; + } + } + + return pucReturn; + } +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + /* + * Send data using a TCP socket. It is not necessary to have the socket + * connected already. Outgoing data will be stored and delivered as soon as + * the socket gets connected. + */ + BaseType_t FreeRTOS_send( Socket_t xSocket, const void *pvBuffer, size_t uxDataLength, BaseType_t xFlags ) + { + BaseType_t xByteCount; + BaseType_t xBytesLeft; + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + TickType_t xRemainingTime; + BaseType_t xTimed = pdFALSE; + TimeOut_t xTimeOut; + BaseType_t xCloseAfterSend; + + /* Prevent compiler warnings about unused parameters. The parameter + may be used in future versions. */ + ( void ) xFlags; + + xByteCount = ( BaseType_t ) prvTCPSendCheck( pxSocket, uxDataLength ); + + if( xByteCount > 0 ) + { + /* xBytesLeft is number of bytes to send, will count to zero. */ + xBytesLeft = ( BaseType_t ) uxDataLength; + + /* xByteCount is number of bytes that can be sent now. */ + xByteCount = ( BaseType_t ) uxStreamBufferGetSpace( pxSocket->u.xTCP.txStream ); + + /* While there are still bytes to be sent. */ + while( xBytesLeft > 0 ) + { + /* If txStream has space. */ + if( xByteCount > 0 ) + { + /* Don't send more than necessary. */ + if( xByteCount > xBytesLeft ) + { + xByteCount = xBytesLeft; + } + + /* Is the close-after-send flag set and is this really the + last transmission? */ + if( ( pxSocket->u.xTCP.bits.bCloseAfterSend != pdFALSE_UNSIGNED ) && ( xByteCount == xBytesLeft ) ) + { + xCloseAfterSend = pdTRUE; + } + else + { + xCloseAfterSend = pdFALSE; + } + + /* The flag 'bCloseAfterSend' can be set before sending data + using setsockopt() + + When the last data packet is being sent out, a FIN flag will + be included to let the peer know that no more data is to be + expected. The use of 'bCloseAfterSend' is not mandatory, it + is just a faster way of transferring files (e.g. when using + FTP). */ + if( xCloseAfterSend != pdFALSE ) + { + /* Now suspend the scheduler: sending the last data and + setting bCloseRequested must be done together */ + vTaskSuspendAll(); + pxSocket->u.xTCP.bits.bCloseRequested = pdTRUE_UNSIGNED; + } + + xByteCount = ( BaseType_t ) uxStreamBufferAdd( pxSocket->u.xTCP.txStream, 0ul, ( const uint8_t * ) pvBuffer, ( size_t ) xByteCount ); + + if( xCloseAfterSend != pdFALSE ) + { + /* Now when the IP-task transmits the data, it will also + see that bCloseRequested is true and include the FIN + flag to start closure of the connection. */ + xTaskResumeAll(); + } + + /* Send a message to the IP-task so it can work on this + socket. Data is sent, let the IP-task work on it. */ + pxSocket->u.xTCP.usTimeout = 1u; + + if( xIsCallingFromIPTask() == pdFALSE ) + { + /* Only send a TCP timer event when not called from the + IP-task. */ + xSendEventToIPTask( eTCPTimerEvent ); + } + + xBytesLeft -= xByteCount; + + if( xBytesLeft == 0 ) + { + break; + } + + /* As there are still bytes left to be sent, increase the + data pointer. */ + pvBuffer = ( void * ) ( ( ( const uint8_t * ) pvBuffer) + xByteCount ); + } + + /* Not all bytes have been sent. In case the socket is marked as + blocking sleep for a while. */ + if( xTimed == pdFALSE ) + { + /* Only in the first round, check for non-blocking. */ + xRemainingTime = pxSocket->xSendBlockTime; + + #if( ipconfigUSE_CALLBACKS != 0 ) + { + if( xIsCallingFromIPTask() != pdFALSE ) + { + /* If this send function is called from within a + call-back handler it may not block, otherwise + chances would be big to get a deadlock: the IP-task + waiting for itself. */ + xRemainingTime = ( TickType_t ) 0; + } + } + #endif /* ipconfigUSE_CALLBACKS */ + + if( xRemainingTime == ( TickType_t ) 0 ) + { + break; + } + + if( ( xFlags & FREERTOS_MSG_DONTWAIT ) != 0 ) + { + break; + } + + /* Don't get here a second time. */ + xTimed = pdTRUE; + + /* Fetch the current time. */ + vTaskSetTimeOutState( &xTimeOut ); + } + else + { + /* Has the timeout been reached? */ + if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE ) + { + break; + } + } + + /* Go sleeping until down-stream events are received. */ + xEventGroupWaitBits( pxSocket->xEventGroup, eSOCKET_SEND | eSOCKET_CLOSED, + pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime ); + + xByteCount = ( BaseType_t ) uxStreamBufferGetSpace( pxSocket->u.xTCP.txStream ); + } + + /* How much was actually sent? */ + xByteCount = ( ( BaseType_t ) uxDataLength ) - xBytesLeft; + + if( xByteCount == 0 ) + { + if( pxSocket->u.xTCP.ucTCPState > eESTABLISHED ) + { + xByteCount = ( BaseType_t ) -pdFREERTOS_ERRNO_ENOTCONN; + } + else + { + if( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) + { + FreeRTOS_debug_printf( ( "FreeRTOS_send: %u -> %lxip:%d: no space\n", + pxSocket->usLocalPort, + pxSocket->u.xTCP.ulRemoteIP, + pxSocket->u.xTCP.usRemotePort ) ); + } + + xByteCount = ( BaseType_t ) -pdFREERTOS_ERRNO_ENOSPC; + } + } + } + + return xByteCount; + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + /* + * Request to put a socket in listen mode + */ + BaseType_t FreeRTOS_listen( Socket_t xSocket, BaseType_t xBacklog ) + { + FreeRTOS_Socket_t *pxSocket; + BaseType_t xResult = 0; + + pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + + /* listen() is allowed for a valid TCP socket in Closed state and already + bound. */ + if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE ) + { + xResult = -pdFREERTOS_ERRNO_EOPNOTSUPP; + } + else if( ( pxSocket->u.xTCP.ucTCPState != eCLOSED ) && ( pxSocket->u.xTCP.ucTCPState != eCLOSE_WAIT ) ) + { + /* Socket is in a wrong state. */ + xResult = -pdFREERTOS_ERRNO_EOPNOTSUPP; + } + else + { + /* Backlog is interpreted here as "the maximum number of child + sockets. */ + pxSocket->u.xTCP.usBacklog = ( uint16_t )FreeRTOS_min_int32( ( int32_t ) 0xffff, ( int32_t ) xBacklog ); + + /* This cleaning is necessary only if a listening socket is being + reused as it might have had a previous connection. */ + if( pxSocket->u.xTCP.bits.bReuseSocket ) + { + if( pxSocket->u.xTCP.rxStream != NULL ) + { + vStreamBufferClear( pxSocket->u.xTCP.rxStream ); + } + + if( pxSocket->u.xTCP.txStream != NULL ) + { + vStreamBufferClear( pxSocket->u.xTCP.txStream ); + } + + memset( pxSocket->u.xTCP.xPacket.u.ucLastPacket, '\0', sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) ); + memset( &pxSocket->u.xTCP.xTCPWindow, '\0', sizeof( pxSocket->u.xTCP.xTCPWindow ) ); + memset( &pxSocket->u.xTCP.bits, '\0', sizeof( pxSocket->u.xTCP.bits ) ); + + /* Now set the bReuseSocket flag again, because the bits have + just been cleared. */ + pxSocket->u.xTCP.bits.bReuseSocket = pdTRUE_UNSIGNED; + } + + vTCPStateChange( pxSocket, eTCP_LISTEN ); + } + + return xResult; + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + /* shutdown - shut down part of a full-duplex connection */ + BaseType_t FreeRTOS_shutdown( Socket_t xSocket, BaseType_t xHow ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + BaseType_t xResult; + + if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE ) + { + /*_RB_ Is this comment correct? The socket is not of a type that + supports the listen() operation. */ + xResult = -pdFREERTOS_ERRNO_EOPNOTSUPP; + } + else if ( pxSocket->u.xTCP.ucTCPState != eESTABLISHED ) + { + /*_RB_ Is this comment correct? The socket is not of a type that + supports the listen() operation. */ + xResult = -pdFREERTOS_ERRNO_EOPNOTSUPP; + } + else + { + pxSocket->u.xTCP.bits.bUserShutdown = pdTRUE_UNSIGNED; + + /* Let the IP-task perform the shutdown of the connection. */ + pxSocket->u.xTCP.usTimeout = 1u; + xSendEventToIPTask( eTCPTimerEvent ); + xResult = 0; + } + (void) xHow; + + return xResult; + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + /* + * A TCP timer has expired, now check all TCP sockets for: + * - Active connect + * - Send a delayed ACK + * - Send new data + * - Send a keep-alive packet + * - Check for timeout (in non-connected states only) + */ + TickType_t xTCPTimerCheck( BaseType_t xWillSleep ) + { + FreeRTOS_Socket_t *pxSocket; + TickType_t xShortest = pdMS_TO_TICKS( ( TickType_t ) ipTCP_TIMER_PERIOD_MS ); + TickType_t xNow = xTaskGetTickCount(); + static TickType_t xLastTime = 0u; + TickType_t xDelta = xNow - xLastTime; + ListItem_t* pxEnd = ( ListItem_t * ) listGET_END_MARKER( &xBoundTCPSocketsList ); + ListItem_t *pxIterator = ( ListItem_t * ) listGET_HEAD_ENTRY( &xBoundTCPSocketsList ); + + xLastTime = xNow; + + if( xDelta == 0u ) + { + xDelta = 1u; + } + + while( pxIterator != pxEnd ) + { + pxSocket = ( FreeRTOS_Socket_t * )listGET_LIST_ITEM_OWNER( pxIterator ); + pxIterator = ( ListItem_t * ) listGET_NEXT( pxIterator ); + + /* Sockets with 'tmout == 0' do not need any regular attention. */ + if( pxSocket->u.xTCP.usTimeout == 0u ) + { + continue; + } + + if( xDelta < ( TickType_t ) pxSocket->u.xTCP.usTimeout ) + { + pxSocket->u.xTCP.usTimeout = ( uint16_t ) ( ( ( TickType_t ) pxSocket->u.xTCP.usTimeout ) - xDelta ); + } + else + { + int rc ; + pxSocket->u.xTCP.usTimeout = 0u; + rc = xTCPSocketCheck( pxSocket ); + + /* Within this function, the socket might want to send a delayed + ack or send out data or whatever it needs to do. */ + if( rc < 0 ) + { + /* Continue because the socket was deleted. */ + continue; + } + } + + /* In xEventBits the driver may indicate that the socket has + important events for the user. These are only done just before the + IP-task goes to sleep. */ + if( pxSocket->xEventBits != 0u ) + { + if( xWillSleep != pdFALSE ) + { + /* The IP-task is about to go to sleep, so messages can be + sent to the socket owners. */ + vSocketWakeUpUser( pxSocket ); + } + else + { + /* Or else make sure this will be called again to wake-up + the sockets' owner. */ + xShortest = ( TickType_t ) 0; + } + } + + if( ( pxSocket->u.xTCP.usTimeout != 0u ) && ( xShortest > ( TickType_t ) pxSocket->u.xTCP.usTimeout ) ) + { + xShortest = ( TickType_t ) pxSocket->u.xTCP.usTimeout; + } + } + + return xShortest; + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + /* + * TCP: as multiple sockets may be bound to the same local port number + * looking up a socket is a little more complex: + * Both a local port, and a remote port and IP address are being used + * For a socket in listening mode, the remote port and IP address are both 0 + */ + FreeRTOS_Socket_t *pxTCPSocketLookup( uint32_t ulLocalIP, UBaseType_t uxLocalPort, uint32_t ulRemoteIP, UBaseType_t uxRemotePort ) + { + ListItem_t *pxIterator; + FreeRTOS_Socket_t *pxResult = NULL, *pxListenSocket = NULL; + MiniListItem_t *pxEnd = ( MiniListItem_t* )listGET_END_MARKER( &xBoundTCPSocketsList ); + + /* Parameter not yet supported. */ + ( void ) ulLocalIP; + + for( pxIterator = ( ListItem_t * ) listGET_NEXT( pxEnd ); + pxIterator != ( ListItem_t * ) pxEnd; + pxIterator = ( ListItem_t * ) listGET_NEXT( pxIterator ) ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator ); + + if( pxSocket->usLocalPort == ( uint16_t ) uxLocalPort ) + { + if( pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN ) + { + /* If this is a socket listening to uxLocalPort, remember it + in case there is no perfect match. */ + pxListenSocket = pxSocket; + } + else if( ( pxSocket->u.xTCP.usRemotePort == ( uint16_t ) uxRemotePort ) && ( pxSocket->u.xTCP.ulRemoteIP == ulRemoteIP ) ) + { + /* For sockets not in listening mode, find a match with + xLocalPort, ulRemoteIP AND xRemotePort. */ + pxResult = pxSocket; + break; + } + } + } + if( pxResult == NULL ) + { + /* An exact match was not found, maybe a listening socket was + found. */ + pxResult = pxListenSocket; + } + + return pxResult; + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + const struct xSTREAM_BUFFER *FreeRTOS_get_rx_buf( Socket_t xSocket ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * )xSocket; + struct xSTREAM_BUFFER *pxReturn = NULL; + + /* Confirm that this is a TCP socket before dereferencing structure + member pointers. */ + if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdFALSE ) == pdTRUE ) + { + pxReturn = pxSocket->u.xTCP.rxStream; + } + + return pxReturn; + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + static StreamBuffer_t *prvTCPCreateStream ( FreeRTOS_Socket_t *pxSocket, BaseType_t xIsInputStream ) + { + StreamBuffer_t *pxBuffer; + size_t uxLength; + size_t uxSize; + + /* Now that a stream is created, the maximum size is fixed before + creation, it could still be changed with setsockopt(). */ + if( xIsInputStream != pdFALSE ) + { + uxLength = pxSocket->u.xTCP.uxRxStreamSize; + + if( pxSocket->u.xTCP.uxLittleSpace == 0ul ) + { + pxSocket->u.xTCP.uxLittleSpace = ( sock20_PERCENT * pxSocket->u.xTCP.uxRxStreamSize ) / sock100_PERCENT; + } + + if( pxSocket->u.xTCP.uxEnoughSpace == 0ul ) + { + pxSocket->u.xTCP.uxEnoughSpace = ( sock80_PERCENT * pxSocket->u.xTCP.uxRxStreamSize ) / sock100_PERCENT; + } + } + else + { + uxLength = pxSocket->u.xTCP.uxTxStreamSize; + } + + /* Add an extra 4 (or 8) bytes. */ + uxLength += sizeof( size_t ); + + /* And make the length a multiple of sizeof( size_t ). */ + uxLength &= ~( sizeof( size_t ) - 1u ); + + uxSize = sizeof( *pxBuffer ) - sizeof( pxBuffer->ucArray ) + uxLength; + + pxBuffer = ( StreamBuffer_t * )pvPortMallocLarge( uxSize ); + + if( pxBuffer == NULL ) + { + FreeRTOS_debug_printf( ( "prvTCPCreateStream: malloc failed\n" ) ); + pxSocket->u.xTCP.bits.bMallocError = pdTRUE_UNSIGNED; + vTCPStateChange( pxSocket, eCLOSE_WAIT ); + } + else + { + /* Clear the markers of the stream */ + memset( pxBuffer, '\0', sizeof( *pxBuffer ) - sizeof( pxBuffer->ucArray ) ); + pxBuffer->LENGTH = ( size_t ) uxLength ; + + if( xTCPWindowLoggingLevel != 0 ) + { + FreeRTOS_debug_printf( ( "prvTCPCreateStream: %cxStream created %lu bytes (total %lu)\n", xIsInputStream ? 'R' : 'T', uxLength, uxSize ) ); + } + + if( xIsInputStream != 0 ) + { + pxSocket->u.xTCP.rxStream = pxBuffer; + } + else + { + pxSocket->u.xTCP.txStream = pxBuffer; + } + } + + return pxBuffer; + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + /* + * Add data to the RxStream. When uxOffset > 0, data has come in out-of-order + * and will be put in front of the head so it can not be popped by the user. + */ + int32_t lTCPAddRxdata( FreeRTOS_Socket_t *pxSocket, size_t uxOffset, const uint8_t *pcData, uint32_t ulByteCount ) + { + StreamBuffer_t *pxStream = pxSocket->u.xTCP.rxStream; + int32_t xResult; + #if( ipconfigUSE_CALLBACKS == 1 ) + BaseType_t bHasHandler = ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleReceive ); + const uint8_t *pucBuffer = NULL; + #endif /* ipconfigUSE_CALLBACKS */ + + /* int32_t uxStreamBufferAdd( pxBuffer, uxOffset, pucData, aCount ) + if( pucData != NULL ) copy data the the buffer + if( pucData == NULL ) no copying, just advance rxHead + if( uxOffset != 0 ) Just store data which has come out-of-order + if( uxOffset == 0 ) Also advance rxHead */ + if( pxStream == NULL ) + { + pxStream = prvTCPCreateStream( pxSocket, pdTRUE ); + if( pxStream == NULL ) + { + return -1; + } + } + + #if( ipconfigUSE_CALLBACKS == 1 ) + { + if( ( bHasHandler != pdFALSE ) && ( uxStreamBufferGetSize( pxStream ) == 0u ) && ( uxOffset == 0ul ) && ( pcData != NULL ) ) + { + /* Data can be passed directly to the user */ + pucBuffer = pcData; + + /* Zero-copy for call-back: no need to add the bytes to the + stream, only the pointer will be advanced by uxStreamBufferAdd(). */ + pcData = NULL; + } + } + #endif /* ipconfigUSE_CALLBACKS */ + + xResult = ( int32_t ) uxStreamBufferAdd( pxStream, uxOffset, pcData, ( size_t ) ulByteCount ); + + #if( ipconfigHAS_DEBUG_PRINTF != 0 ) + { + if( xResult != ( int32_t ) ulByteCount ) + { + FreeRTOS_debug_printf( ( "lTCPAddRxdata: at %ld: %ld/%lu bytes (tail %lu head %lu space %lu front %lu)\n", + uxOffset, xResult, ulByteCount, + pxStream->uxTail, + pxStream->uxHead, + uxStreamBufferFrontSpace( pxStream ), + pxStream->uxFront ) ); + } + } + #endif /* ipconfigHAS_DEBUG_PRINTF */ + + if( uxOffset == 0u ) + { + /* Data is being added to rxStream at the head (offs = 0) */ + #if( ipconfigUSE_CALLBACKS == 1 ) + if( bHasHandler != pdFALSE ) + { + /* The socket owner has installed an OnReceive handler. Pass the + Rx data, without copying from the rxStream, to the user. */ + for (;;) + { + uint8_t *ucReadPtr = NULL; + uint32_t ulCount; + if( pucBuffer != NULL ) + { + ucReadPtr = ( uint8_t * )pucBuffer; + ulCount = ulByteCount; + pucBuffer = NULL; + } + else + { + ulCount = ( uint32_t ) uxStreamBufferGetPtr( pxStream, &( ucReadPtr ) ); + } + + if( ulCount == 0ul ) + { + break; + } + + pxSocket->u.xTCP.pxHandleReceive( ( Socket_t )pxSocket, ( void* )ucReadPtr, ( size_t ) ulCount ); + uxStreamBufferGet( pxStream, 0ul, NULL, ( size_t ) ulCount, pdFALSE ); + } + } else + #endif /* ipconfigUSE_CALLBACKS */ + { + /* See if running out of space. */ + if( pxSocket->u.xTCP.bits.bLowWater == pdFALSE_UNSIGNED ) + { + size_t uxFrontSpace = uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream ); + if( uxFrontSpace <= pxSocket->u.xTCP.uxLittleSpace ) + { + pxSocket->u.xTCP.bits.bLowWater = pdTRUE_UNSIGNED; + pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED; + + /* bLowWater was reached, send the changed window size. */ + pxSocket->u.xTCP.usTimeout = 1u; + xSendEventToIPTask( eTCPTimerEvent ); + } + } + + /* New incoming data is available, wake up the user. User's + semaphores will be set just before the IP-task goes asleep. */ + pxSocket->xEventBits |= eSOCKET_RECEIVE; + + #if ipconfigSUPPORT_SELECT_FUNCTION == 1 + { + if( ( pxSocket->xSelectBits & eSELECT_READ ) != 0 ) + { + pxSocket->xEventBits |= ( eSELECT_READ << SOCKET_EVENT_BIT_COUNT ); + } + } + #endif + } + } + + return xResult; + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + /* Function to get the remote address and IP port */ + BaseType_t FreeRTOS_GetRemoteAddress( Socket_t xSocket, struct freertos_sockaddr *pxAddress ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + BaseType_t xResult; + + if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + xResult = -pdFREERTOS_ERRNO_EINVAL; + } + else + { + /* BSD style sockets communicate IP and port addresses in network + byte order. + + IP address of remote machine. */ + pxAddress->sin_addr = FreeRTOS_htonl ( pxSocket->u.xTCP.ulRemoteIP ); + + /* Port on remote machine. */ + pxAddress->sin_port = FreeRTOS_htons ( pxSocket->u.xTCP.usRemotePort ); + + xResult = ( BaseType_t ) sizeof( ( *pxAddress ) ); + } + + return xResult; + } + +#endif /* ipconfigUSE_TCP */ + +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + /* Returns the number of bytes that may be added to txStream */ + BaseType_t FreeRTOS_maywrite( Socket_t xSocket ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + BaseType_t xResult; + + if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + xResult = -pdFREERTOS_ERRNO_EINVAL; + } + else if( pxSocket->u.xTCP.ucTCPState != eESTABLISHED ) + { + if( ( pxSocket->u.xTCP.ucTCPState < eCONNECT_SYN ) || ( pxSocket->u.xTCP.ucTCPState > eESTABLISHED ) ) + { + xResult = -1; + } + else + { + xResult = 0; + } + } + else if( pxSocket->u.xTCP.txStream == NULL ) + { + xResult = ( BaseType_t ) pxSocket->u.xTCP.uxTxStreamSize; + } + else + { + xResult = ( BaseType_t ) uxStreamBufferGetSpace( pxSocket->u.xTCP.txStream ); + } + + return xResult; + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP ==1 ) + + BaseType_t FreeRTOS_tx_space( Socket_t xSocket ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + BaseType_t xReturn; + + if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + xReturn = -pdFREERTOS_ERRNO_EINVAL; + } + else + { + if( pxSocket->u.xTCP.txStream != NULL ) + { + xReturn = ( BaseType_t ) uxStreamBufferGetSpace ( pxSocket->u.xTCP.txStream ); + } + else + { + xReturn = ( BaseType_t ) pxSocket->u.xTCP.uxTxStreamSize; + } + } + + return xReturn; + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + BaseType_t FreeRTOS_tx_size( Socket_t xSocket ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + BaseType_t xReturn; + + if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + xReturn = -pdFREERTOS_ERRNO_EINVAL; + } + else + { + if( pxSocket->u.xTCP.txStream != NULL ) + { + xReturn = ( BaseType_t ) uxStreamBufferGetSize ( pxSocket->u.xTCP.txStream ); + } + else + { + xReturn = 0; + } + } + + return xReturn; + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + /* Returns pdTRUE if TCP socket is connected. */ + BaseType_t FreeRTOS_issocketconnected( Socket_t xSocket ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + BaseType_t xReturn = pdFALSE; + + if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + xReturn = -pdFREERTOS_ERRNO_EINVAL; + } + else + { + if( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) + { + if( pxSocket->u.xTCP.ucTCPState < eCLOSE_WAIT ) + { + xReturn = pdTRUE; + } + } + } + + return xReturn; + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + /* returns the actual size of MSS being used */ + BaseType_t FreeRTOS_mss( Socket_t xSocket ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + BaseType_t xReturn; + + if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + xReturn = -pdFREERTOS_ERRNO_EINVAL; + } + else + { + /* usCurMSS is declared as uint16_t to save space. FreeRTOS_mss() + will often be used in signed native-size expressions cast it to + BaseType_t. */ + xReturn = ( BaseType_t ) ( pxSocket->u.xTCP.usCurMSS ); + } + + return xReturn; + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + /* HT: for internal use only: return the connection status */ + BaseType_t FreeRTOS_connstatus( Socket_t xSocket ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + BaseType_t xReturn; + + if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + xReturn = -pdFREERTOS_ERRNO_EINVAL; + } + else + { + /* Cast it to BaseType_t */ + xReturn = ( BaseType_t ) ( pxSocket->u.xTCP.ucTCPState ); + } + + return xReturn; + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + /* + * Returns the number of bytes which can be read. + */ + BaseType_t FreeRTOS_rx_size( Socket_t xSocket ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + BaseType_t xReturn; + + if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + xReturn = -pdFREERTOS_ERRNO_EINVAL; + } + else if( pxSocket->u.xTCP.rxStream != NULL ) + { + xReturn = ( BaseType_t ) uxStreamBufferGetSize( pxSocket->u.xTCP.rxStream ); + } + else + { + xReturn = 0; + } + + return xReturn; + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + void FreeRTOS_netstat( void ) + { + IPStackEvent_t xAskEvent; + + /* Ask the IP-task to call vTCPNetStat() + * to avoid accessing xBoundTCPSocketsList + */ + xAskEvent.eEventType = eTCPNetStat; + xAskEvent.pvData = ( void * ) NULL; + xSendEventStructToIPTask( &xAskEvent, 1000u ); + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ( ipconfigHAS_PRINTF != 0 ) && ( ipconfigUSE_TCP == 1 ) ) + + void vTCPNetStat( void ) + { + /* Show a simple listing of all created sockets and their connections */ + ListItem_t *pxIterator; + BaseType_t count = 0; + + if( listLIST_IS_INITIALISED( &xBoundTCPSocketsList ) == pdFALSE ) + { + FreeRTOS_printf( ( "PLUS-TCP not initialized\n" ) ); + } + else + { + FreeRTOS_printf( ( "Prot Port IP-Remote : Port R/T Status Alive tmout Child\n" ) ); + for( pxIterator = ( ListItem_t * ) listGET_HEAD_ENTRY( &xBoundTCPSocketsList ); + pxIterator != ( ListItem_t * ) listGET_END_MARKER( &xBoundTCPSocketsList ); + pxIterator = ( ListItem_t * ) listGET_NEXT( pxIterator ) ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator ); + #if( ipconfigTCP_KEEP_ALIVE == 1 ) + TickType_t age = xTaskGetTickCount() - pxSocket->u.xTCP.xLastAliveTime; + #else + TickType_t age = 0u; + #endif + #if( ipconfigUSE_CALLBACKS == 1 ) + void *pxHandleReceive = (void*)pxSocket->u.xTCP.pxHandleReceive; + #else + void *pxHandleReceive = (void*)NULL; + #endif + char ucChildText[16] = ""; + if (pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN) + { + const int32_t copied_len = snprintf( ucChildText, sizeof( ucChildText ), " %d/%d", + ( int ) pxSocket->u.xTCP.usChildCount, + ( int ) pxSocket->u.xTCP.usBacklog); + /* These should never evaluate to false since the buffers are both shorter than 5-6 characters (<=65535) */ + configASSERT( copied_len >= 0 ); + configASSERT( copied_len < sizeof( ucChildText ) ); + } + FreeRTOS_printf( ( "TCP %5d %-16lxip:%5d %d/%d %-13.13s %6lu %6u%s\n", + pxSocket->usLocalPort, /* Local port on this machine */ + pxSocket->u.xTCP.ulRemoteIP, /* IP address of remote machine */ + pxSocket->u.xTCP.usRemotePort, /* Port on remote machine */ + pxSocket->u.xTCP.rxStream != NULL, + pxSocket->u.xTCP.txStream != NULL, + FreeRTOS_GetTCPStateName( pxSocket->u.xTCP.ucTCPState ), + (age > 999999 ? 999999 : age), /* Format 'age' for printing */ + pxSocket->u.xTCP.usTimeout, + ucChildText ) ); + /* Remove compiler warnings if FreeRTOS_debug_printf() is not defined. */ + ( void ) pxHandleReceive; + count++; + } + + for( pxIterator = ( ListItem_t * ) listGET_HEAD_ENTRY( &xBoundUDPSocketsList ); + pxIterator != ( ListItem_t * ) listGET_END_MARKER( &xBoundUDPSocketsList ); + pxIterator = ( ListItem_t * ) listGET_NEXT( pxIterator ) ) + { + /* Local port on this machine */ + FreeRTOS_printf( ( "UDP Port %5u\n", + FreeRTOS_ntohs( listGET_LIST_ITEM_VALUE( pxIterator ) ) ) ); + count++; + } + + FreeRTOS_printf( ( "FreeRTOS_netstat: %lu sockets %lu < %lu < %d buffers free\n", + count, + uxGetMinimumFreeNetworkBuffers( ), + uxGetNumberOfFreeNetworkBuffers( ), + ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ) ); + } + } + +#endif /* ( ( ipconfigHAS_PRINTF != 0 ) && ( ipconfigUSE_TCP == 1 ) ) */ +/*-----------------------------------------------------------*/ + +#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) + + void vSocketSelect( SocketSelect_t *pxSocketSet ) + { + BaseType_t xRound; + EventBits_t xSocketBits, xBitsToClear; + #if ipconfigUSE_TCP == 1 + BaseType_t xLastRound = 1; + #else + BaseType_t xLastRound = 0; + #endif + + /* These flags will be switched on after checking the socket status. */ + EventBits_t xGroupBits = 0; + pxSocketSet->pxSocket = NULL; + + for( xRound = 0; xRound <= xLastRound; xRound++ ) + { + const ListItem_t *pxIterator; + const MiniListItem_t *pxEnd; + if( xRound == 0 ) + { + pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( &xBoundUDPSocketsList ); + } + #if ipconfigUSE_TCP == 1 + else + { + pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( &xBoundTCPSocketsList ); + } + #endif /* ipconfigUSE_TCP == 1 */ + for( pxIterator = ( const ListItem_t * ) ( listGET_NEXT( pxEnd ) ); + pxIterator != ( const ListItem_t * ) pxEnd; + pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator ); + if( pxSocket->pxSocketSet != pxSocketSet ) + { + /* Socket does not belong to this select group. */ + continue; + } + xSocketBits = 0; + + #if( ipconfigUSE_TCP == 1 ) + if( pxSocket->ucProtocol == FREERTOS_IPPROTO_TCP ) + { + /* Check if the socket has already been accepted by the + owner. If not, it is useless to return it from a + select(). */ + BaseType_t bAccepted = pdFALSE; + + if( pxSocket->u.xTCP.bits.bPassQueued == pdFALSE_UNSIGNED ) + { + if( pxSocket->u.xTCP.bits.bPassAccept == pdFALSE_UNSIGNED ) + { + bAccepted = pdTRUE; + } + } + + /* Is the set owner interested in READ events? */ + if( ( pxSocket->xSelectBits & eSELECT_READ ) != 0 ) + { + if( pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN ) + { + if( ( pxSocket->u.xTCP.pxPeerSocket != NULL ) && ( pxSocket->u.xTCP.pxPeerSocket->u.xTCP.bits.bPassAccept != 0 ) ) + { + xSocketBits |= eSELECT_READ; + } + } + else if( ( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED ) && ( pxSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) ) + { + /* This socket has the re-use flag. After connecting it turns into + aconnected socket. Set the READ event, so that accept() will be called. */ + xSocketBits |= eSELECT_READ; + } + else if( ( bAccepted != 0 ) && ( FreeRTOS_recvcount( pxSocket ) > 0 ) ) + { + xSocketBits |= eSELECT_READ; + } + } + /* Is the set owner interested in EXCEPTION events? */ + if( ( pxSocket->xSelectBits & eSELECT_EXCEPT ) != 0 ) + { + if( ( pxSocket->u.xTCP.ucTCPState == eCLOSE_WAIT ) || ( pxSocket->u.xTCP.ucTCPState == eCLOSED ) ) + { + xSocketBits |= eSELECT_EXCEPT; + } + } + + /* Is the set owner interested in WRITE events? */ + if( ( pxSocket->xSelectBits & eSELECT_WRITE ) != 0 ) + { + BaseType_t bMatch = pdFALSE; + + if( bAccepted != 0 ) + { + if( FreeRTOS_tx_space( pxSocket ) > 0 ) + { + bMatch = pdTRUE; + } + } + + if( bMatch == pdFALSE ) + { + if( ( pxSocket->u.xTCP.bits.bConnPrepared != pdFALSE_UNSIGNED ) && + ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) && + ( pxSocket->u.xTCP.bits.bConnPassed == pdFALSE_UNSIGNED ) ) + { + pxSocket->u.xTCP.bits.bConnPassed = pdTRUE_UNSIGNED; + bMatch = pdTRUE; + } + } + + if( bMatch != pdFALSE ) + { + xSocketBits |= eSELECT_WRITE; + } + } + } + else + #endif /* ipconfigUSE_TCP == 1 */ + { + /* Select events for UDP are simpler. */ + if( ( ( pxSocket->xSelectBits & eSELECT_READ ) != 0 ) && + ( listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ) > 0U ) ) + { + xSocketBits |= eSELECT_READ; + } + /* The WRITE and EXCEPT bits are not used for UDP */ + } /* if( pxSocket->ucProtocol == FREERTOS_IPPROTO_TCP ) */ + + /* Each socket keeps its own event flags, which are looked-up + by FreeRTOS_FD_ISSSET() */ + pxSocket->xSocketBits = xSocketBits; + + /* The ORed value will be used to set the bits in the event + group. */ + xGroupBits |= xSocketBits; + + } /* for( pxIterator ... ) */ + } /* for( xRound = 0; xRound <= xLastRound; xRound++ ) */ + + xBitsToClear = xEventGroupGetBits( pxSocketSet->xSelectGroup ); + + /* Now set the necessary bits. */ + xBitsToClear = ( xBitsToClear & ~xGroupBits ) & eSELECT_ALL; + + #if( ipconfigSUPPORT_SIGNALS != 0 ) + { + /* Maybe the socketset was signalled, but don't + clear the 'eSELECT_INTR' bit here, as it will be used + and cleared in FreeRTOS_select(). */ + xBitsToClear &= ( EventBits_t ) ~eSELECT_INTR; + } + #endif /* ipconfigSUPPORT_SIGNALS */ + + if( xBitsToClear != 0 ) + { + xEventGroupClearBits( pxSocketSet->xSelectGroup, xBitsToClear ); + } + + /* Now include eSELECT_CALL_IP to wakeup the caller. */ + xEventGroupSetBits( pxSocketSet->xSelectGroup, xGroupBits | eSELECT_CALL_IP ); + } + +#endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigSUPPORT_SIGNALS != 0 ) + + /* Send a signal to the task which reads from this socket. */ + BaseType_t FreeRTOS_SignalSocket( Socket_t xSocket ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + BaseType_t xReturn; + + if( pxSocket == NULL ) + { + xReturn = -pdFREERTOS_ERRNO_EINVAL; + } + else + #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) + if( ( pxSocket->pxSocketSet != NULL ) && ( pxSocket->pxSocketSet->xSelectGroup != NULL ) ) + { + xEventGroupSetBits( pxSocket->pxSocketSet->xSelectGroup, eSELECT_INTR ); + xReturn = 0; + } + else + #endif /* ipconfigSUPPORT_SELECT_FUNCTION */ + if( pxSocket->xEventGroup != NULL ) + { + xEventGroupSetBits( pxSocket->xEventGroup, eSOCKET_INTR ); + xReturn = 0; + } + else + { + xReturn = -pdFREERTOS_ERRNO_EINVAL; + } + + return xReturn; + } + +#endif /* ipconfigSUPPORT_SIGNALS */ +/*-----------------------------------------------------------*/ + +#if( ipconfigSUPPORT_SIGNALS != 0 ) + + /* Send a signal to the task which reads from this socket (FromISR version). */ + BaseType_t FreeRTOS_SignalSocketFromISR( Socket_t xSocket, BaseType_t *pxHigherPriorityTaskWoken ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + BaseType_t xReturn; + IPStackEvent_t xEvent; + extern QueueHandle_t xNetworkEventQueue; + + configASSERT( pxSocket != NULL ); + configASSERT( pxSocket->ucProtocol == FREERTOS_IPPROTO_TCP ); + configASSERT( pxSocket->xEventGroup ); + + xEvent.eEventType = eSocketSignalEvent; + xEvent.pvData = ( void * )pxSocket; + + /* The IP-task will call FreeRTOS_SignalSocket for this socket. */ + xReturn = xQueueSendToBackFromISR( xNetworkEventQueue, &xEvent, pxHigherPriorityTaskWoken ); + + return xReturn; + } + +#endif /* ipconfigSUPPORT_SIGNALS */ +/*-----------------------------------------------------------*/