/*\r
- * FreeRTOS+TCP V2.0.0\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
* 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. If you wish to use our Amazon\r
- * FreeRTOS name, please do so in a fair use way that does not cause confusion.\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
* 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://www.FreeRTOS.org\r
* http://aws.amazon.com/freertos\r
- *\r
- * 1 tab == 4 spaces!\r
+ * http://www.FreeRTOS.org\r
*/\r
\r
/* Standard includes. */\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
+#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
-/* _HT_ thinks that the default of 0xc000 is pretty high */\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 ) 0xc000 )\r
+ #define socketAUTO_PORT_ALLOCATION_START_NUMBER ( ( uint16_t ) 0x0400 )\r
#endif\r
\r
-/* When the automatically generated port numbers overflow, the next value used\r
-is not set back to socketAUTO_PORT_ALLOCATION_START_NUMBER because it is likely\r
-that the first few automatically generated ports will still be in use. Instead\r
-it is reset back to the value defined by this constant. */\r
-#define socketAUTO_PORT_ALLOCATION_RESET_NUMBER ( ( uint16_t ) 0xc100 )\r
-#define socketAUTO_PORT_ALLOCATION_MAX_NUMBER ( ( uint16_t ) 0xff00 )\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
List_t xBoundTCPSocketsList;\r
#endif /* ipconfigUSE_TCP == 1 */\r
\r
-/* Holds the next private port number to use when binding a client socket for\r
-UDP, and if ipconfigUSE_TCP is set to 1, also TCP. UDP uses index\r
-socketNEXT_UDP_PORT_NUMBER_INDEX and TCP uses index\r
-socketNEXT_TCP_PORT_NUMBER_INDEX. The initial value is set to be between\r
-socketAUTO_PORT_ALLOCATION_RESET_NUMBER and socketAUTO_PORT_ALLOCATION_MAX_NUMBER\r
-when the IP stack is initialised. Note ipconfigRAND32() is used, which must be\r
-seeded prior to the IP task being started. */\r
-static uint16_t usNextPortToUse[ socketPROTOCOL_COUNT ] = { 0 };\r
-\r
/*-----------------------------------------------------------*/\r
\r
static BaseType_t prvValidSocket( FreeRTOS_Socket_t *pxSocket, BaseType_t xProtocol, BaseType_t xIsBound )\r
}\r
/*-----------------------------------------------------------*/\r
\r
-void vNetworkSocketsInit( void )\r
+BaseType_t vNetworkSocketsInit( void )\r
{\r
-const uint32_t ulAutoPortRange = socketAUTO_PORT_ALLOCATION_MAX_NUMBER - socketAUTO_PORT_ALLOCATION_RESET_NUMBER;\r
-uint32_t ulRandomPort;\r
-\r
vListInitialise( &xBoundUDPSocketsList );\r
\r
- /* Determine the first anonymous UDP port number to get assigned. Give it\r
- a random value in order to avoid confusion about port numbers being used\r
- earlier, before rebooting the device. Start with the first auto port\r
- number, then add a random offset up to a maximum of the range of numbers. */\r
- ulRandomPort = socketAUTO_PORT_ALLOCATION_START_NUMBER;\r
- ulRandomPort += ( ipconfigRAND32() % ulAutoPortRange );\r
- usNextPortToUse[ socketNEXT_UDP_PORT_NUMBER_INDEX ] = ( uint16_t ) ulRandomPort;\r
-\r
#if( ipconfigUSE_TCP == 1 )\r
{\r
- extern uint32_t ulNextInitialSequenceNumber;\r
-\r
- ulNextInitialSequenceNumber = ipconfigRAND32();\r
-\r
- /* Determine the first anonymous TCP port number to get assigned. */\r
- ulRandomPort = socketAUTO_PORT_ALLOCATION_START_NUMBER;\r
- ulRandomPort += ( ipconfigRAND32() % ulAutoPortRange );\r
- usNextPortToUse[ socketNEXT_TCP_PORT_NUMBER_INDEX ] = ( uint16_t ) ulRandomPort;\r
-\r
vListInitialise( &xBoundTCPSocketsList );\r
}\r
#endif /* ipconfigUSE_TCP == 1 */\r
+\r
+ return pdTRUE;\r
}\r
/*-----------------------------------------------------------*/\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
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
else\r
{\r
xReturn = pdFAIL;\r
+ configASSERT( xReturn );\r
}\r
}\r
/* In case configASSERT() is not used */\r
}\r
else\r
{\r
- /* Clear the entire space to avoid nulling individual entries. */\r
+ /* Clear the entire space to avoid nulling individual entries */\r
memset( pxSocket, '\0', uxSocketSize );\r
\r
pxSocket->xEventGroup = xEventGroup;\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->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
+ pxSocket->ucProtocol = ( uint8_t ) xProtocol; /* protocol: UDP or TCP */\r
\r
#if( ipconfigUSE_TCP == 1 )\r
{\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.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( 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 to the socket. There is a very tiny chance that the allocated\r
- port will already be in use - if that is the case, then the check below\r
- [pxListFindListItemWithValue()] will result in an error being returned. */\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
- /* For now, put it to zero, will be assigned later */\r
+ /* Put the port to zero to be assigned later. */\r
pxAddress->sin_port = 0u;\r
}\r
}\r
{\r
if( pxAddress->sin_port == 0u )\r
{\r
- pxAddress->sin_port = prvGetPrivatePortNumber( ( BaseType_t ) pxSocket->ucProtocol );\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
case FREERTOS_SO_SET_SEMAPHORE:\r
{\r
pxSocket->pxUserSemaphore = *( ( SemaphoreHandle_t * ) pvOptionValue );\r
+ xReturn = 0;\r
}\r
- xReturn = 0;\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_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
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.ulRxWindowLength = pxSocket->u.xTCP.uxTxWinSize * pxSocket->u.xTCP.usInitMSS;\r
+ pxSocket->u.xTCP.xTCPWindow.xSize.ulTxWindowLength = pxSocket->u.xTCP.uxTxWinSize * pxSocket->u.xTCP.usInitMSS;\r
}\r
}\r
\r
\r
/*-----------------------------------------------------------*/\r
\r
-/* Get a free private ('anonymous') port number */\r
+/* Find an available port number per https://tools.ietf.org/html/rfc6056. */\r
static uint16_t prvGetPrivatePortNumber( BaseType_t xProtocol )\r
{\r
-uint16_t usResult;\r
-BaseType_t xIndex;\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
- xIndex = socketNEXT_TCP_PORT_NUMBER_INDEX;\r
pxList = &xBoundTCPSocketsList;\r
}\r
else\r
#endif\r
{\r
- xIndex = socketNEXT_UDP_PORT_NUMBER_INDEX;\r
pxList = &xBoundUDPSocketsList;\r
}\r
\r
/* Avoid compiler warnings if ipconfigUSE_TCP is not defined. */\r
( void ) xProtocol;\r
\r
- /* Assign the next port in the range. Has it overflowed? */\r
- /*_RB_ This needs to be randomised rather than sequential. */\r
- /* _HT_ Agreed, although many OS's use sequential port numbers, see\r
- https://www.cymru.com/jtk/misc/ephemeralports.html */\r
- for ( ;; )\r
+ /* Find the next available port using the random seed as a starting\r
+ point. */\r
+ do\r
{\r
- ++( usNextPortToUse[ xIndex ] );\r
+ /* Generate a random seed. */\r
+ ulRandomSeed = ipconfigRAND32( );\r
\r
- if( usNextPortToUse[ xIndex ] >= socketAUTO_PORT_ALLOCATION_MAX_NUMBER )\r
+ /* Only proceed if the random number generator succeeded. */\r
+ if( 0 == ulRandomSeed )\r
{\r
- /* Don't go right back to the start of the dynamic/private port\r
- range numbers as any persistent sockets are likely to have been\r
- create first so the early port numbers may still be in use. */\r
- usNextPortToUse[ xIndex ] = socketAUTO_PORT_ALLOCATION_RESET_NUMBER;\r
+ if( pdFALSE == xGotZeroOnce )\r
+ {\r
+ xGotZeroOnce = pdTRUE;\r
+ continue;\r
+ }\r
+ else\r
+ {\r
+ break;\r
+ }\r
}\r
\r
- usResult = FreeRTOS_htons( usNextPortToUse[ xIndex ] );\r
+ /* Map the random to a candidate port. */\r
+ usResult =\r
+ socketAUTO_PORT_ALLOCATION_START_NUMBER +\r
+ ( ( ( uint16_t )ulRandomSeed ) % usEphemeralPortCount );\r
\r
- if( pxListFindListItemWithValue( pxList, ( TickType_t ) usResult ) == NULL )\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
-} /* Tested */\r
+}\r
/*-----------------------------------------------------------*/\r
\r
/* pxListFindListItemWithValue: find a list item in a bound socket list\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
/* 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 useful in systems with a minimum of RAM and\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
creation, it could still be changed with setsockopt(). */\r
if( xIsInputStream != pdFALSE )\r
{\r
- /* Flow control for input streams works with a low- and a high-water mark.\r
- 1) If the RX-space becomes less than uxLittleSpace, the flag 'bLowWater' will\r
- be set, and a TCP window update message will be sent to the peer.\r
- 2) The data will be read from the socket by recv() and when RX-space becomes\r
- larger than or equal to than 'uxEnoughSpace', a new TCP window update\r
- message will be sent to the peer, and 'bLowWater' will get cleared again.\r
- By default:\r
- uxLittleSpace == 1/5 x uxRxStreamSize\r
- uxEnoughSpace == 4/5 x uxRxStreamSize\r
- How-ever it is very inefficient to make 'uxLittleSpace' smaller than the actual MSS.\r
- */\r
uxLength = pxSocket->u.xTCP.uxRxStreamSize;\r
\r
if( pxSocket->u.xTCP.uxLittleSpace == 0ul )\r
{\r
pxSocket->u.xTCP.uxLittleSpace = ( 1ul * pxSocket->u.xTCP.uxRxStreamSize ) / 5u; /*_RB_ Why divide by 5? Can this be changed to a #define? */\r
- if( (pxSocket->u.xTCP.uxLittleSpace < pxSocket->u.xTCP.usCurMSS ) && ( pxSocket->u.xTCP.uxRxStreamSize >= 2 * pxSocket->u.xTCP.usCurMSS ) )\r
- {\r
- pxSocket->u.xTCP.uxLittleSpace = pxSocket->u.xTCP.usCurMSS;\r
- }\r
}\r
\r
if( pxSocket->u.xTCP.uxEnoughSpace == 0ul )\r
break;\r
}\r
\r
- if( pxSocket->u.xTCP.pxHandleReceive( (Socket_t *)pxSocket, ( void* )ucReadPtr, ( size_t ) ulCount ) != pdFALSE )\r
- {\r
- uxStreamBufferGet( pxStream, 0ul, NULL, ( size_t ) ulCount, pdFALSE );\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
else\r
{\r
- FreeRTOS_printf( ( "Prot Port IP-Remote : Port R/T Status Alive tmout Child\n" ) );\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
char ucChildText[16] = "";\r
if (pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN)\r
{\r
- snprintf( ucChildText, sizeof( ucChildText ), " %d/%d",\r
- pxSocket->u.xTCP.usChildCount,\r
- pxSocket->u.xTCP.usBacklog);\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
- if( age > 999999 )\r
- age = 999999;\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.rxStream != NULL,\r
pxSocket->u.xTCP.txStream != NULL,\r
FreeRTOS_GetTCPStateName( pxSocket->u.xTCP.ucTCPState ),\r
- age,\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