]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_Sockets.c
Update version number in +TCP code.
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / FreeRTOS_Sockets.c
index e40ce8d5f472df93a0b32566b8e873f860beaee1..ce03f613692b5872250fae9d4235a10a2c59a86c 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
- * FreeRTOS+TCP V2.0.1\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
  * 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
@@ -50,24 +48,22 @@ port number. */
 \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
@@ -167,15 +163,6 @@ List_t xBoundUDPSocketsList;
        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
@@ -201,35 +188,17 @@ BaseType_t xReturn = pdTRUE;
 }\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
@@ -263,6 +232,7 @@ FreeRTOS_Socket_t *pxSocket;
                        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
@@ -273,6 +243,7 @@ FreeRTOS_Socket_t *pxSocket;
                        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
@@ -281,6 +252,7 @@ FreeRTOS_Socket_t *pxSocket;
                else\r
                {\r
                        xReturn = pdFAIL;\r
+                       configASSERT( xReturn );\r
                }\r
        }\r
        /* In case configASSERT() is not used */\r
@@ -322,7 +294,7 @@ Socket_t xReturn;
                }\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
@@ -345,9 +317,9 @@ Socket_t xReturn;
                        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
@@ -355,7 +327,7 @@ Socket_t xReturn;
                                {\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
@@ -1018,14 +990,12 @@ List_t *pxSocketList;
        #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
@@ -1039,7 +1009,11 @@ List_t *pxSocketList;
        {\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
@@ -1526,7 +1500,7 @@ FreeRTOS_Socket_t *pxSocket;
                                        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
@@ -1633,54 +1607,77 @@ FreeRTOS_Socket_t *pxSocket;
 \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
@@ -1891,7 +1888,7 @@ void vSocketWakeUpUser( FreeRTOS_Socket_t *pxSocket )
        /* 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
@@ -2875,7 +2872,7 @@ void vSocketWakeUpUser( FreeRTOS_Socket_t *pxSocket )
 \r
 #if( ipconfigUSE_TCP == 1 )\r
 \r
-       static StreamBuffer_t *prvTCPCreateStream( FreeRTOS_Socket_t *pxSocket, BaseType_t xIsInputStream )\r
+       static StreamBuffer_t *prvTCPCreateStream ( FreeRTOS_Socket_t *pxSocket, BaseType_t xIsInputStream )\r
        {\r
        StreamBuffer_t *pxBuffer;\r
        size_t uxLength;\r
@@ -2885,26 +2882,11 @@ void vSocketWakeUpUser( FreeRTOS_Socket_t *pxSocket )
                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 >= 2u * 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
@@ -3047,10 +3029,8 @@ void vSocketWakeUpUser( FreeRTOS_Socket_t *pxSocket )
                                                        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
@@ -3359,7 +3339,7 @@ void vSocketWakeUpUser( FreeRTOS_Socket_t *pxSocket )
                }\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
@@ -3378,12 +3358,13 @@ void vSocketWakeUpUser( FreeRTOS_Socket_t *pxSocket )
                                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
@@ -3391,7 +3372,7 @@ void vSocketWakeUpUser( FreeRTOS_Socket_t *pxSocket )
                                        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