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