/* * FreeRTOS V202211.00 * Copyright (C) 2020 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. * * https://www.FreeRTOS.org * https://github.com/FreeRTOS * */ /* * http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading * the FAQ page "My application does not run, what could be wrong?". Have you * defined configASSERT()? * * http://www.FreeRTOS.org/support - In return for receiving this top quality * embedded software for free we request you assist our global community by * participating in the support forum. * * http://www.FreeRTOS.org/training - Investing in training allows your team to * be as productive as possible as early as possible. Now you can receive * FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers * Ltd, and the world's leading authority on the world's leading RTOS. * * http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, * including FreeRTOS+Trace - an indispensable productivity tool, a DOS * compatible FAT file system, and our tiny thread aware UDP/IP stack. * * http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. * Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. * * http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High * Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS * licenses offer ticketed support, indemnification and commercial middleware. * * http://www.SafeRTOS.com - High Integrity Systems also provide a safety * engineered and independently SIL3 certified version for use in safety and * mission critical applications that require provable dependability. * */ /* * FreeRTOS tasks are used with FreeRTOS+TCP to create a TCP echo server on the * standard echo port number (7). * * See the following web page for essential demo usage and configuration * details: * https://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_Echo_Server.html */ /* Standard includes. */ #include #include #include /* FreeRTOS includes. */ #include "FreeRTOS.h" #include "task.h" #include "semphr.h" /* FreeRTOS+TCP includes. */ #include "FreeRTOS_IP.h" #include "FreeRTOS_Sockets.h" /* Remove the whole file if FreeRTOSIPConfig.h is set to exclude TCP. */ #if ( ipconfigUSE_TCP == 1 ) /* The maximum time to wait for a closing socket to close. */ #define tcpechoSHUTDOWN_DELAY ( pdMS_TO_TICKS( 5000 ) ) /* The standard echo port number. */ #define tcpechoPORT_NUMBER 7 /* If ipconfigUSE_TCP_WIN is 1 then the Tx sockets will use a buffer size set by * ipconfigTCP_TX_BUFFER_LENGTH, and the Tx window size will be * configECHO_SERVER_TX_WINDOW_SIZE times the buffer size. Note * ipconfigTCP_TX_BUFFER_LENGTH is set in FreeRTOSIPConfig.h as it is a standard TCP/IP * stack constant, whereas configECHO_SERVER_TX_WINDOW_SIZE is set in * FreeRTOSConfig.h as it is a demo application constant. */ #ifndef configECHO_SERVER_TX_WINDOW_SIZE #define configECHO_SERVER_TX_WINDOW_SIZE 2 #endif /* If ipconfigUSE_TCP_WIN is 1 then the Rx sockets will use a buffer size set by * ipconfigTCP_RX_BUFFER_LENGTH, and the Rx window size will be * configECHO_SERVER_RX_WINDOW_SIZE times the buffer size. Note * ipconfigTCP_RX_BUFFER_LENGTH is set in FreeRTOSIPConfig.h as it is a standard TCP/IP * stack constant, whereas configECHO_SERVER_RX_WINDOW_SIZE is set in * FreeRTOSConfig.h as it is a demo application constant. */ #ifndef configECHO_SERVER_RX_WINDOW_SIZE #define configECHO_SERVER_RX_WINDOW_SIZE 2 #endif /*-----------------------------------------------------------*/ /* * Uses FreeRTOS+TCP to listen for incoming echo connections, creating a task * to handle each connection. */ static void prvConnectionListeningTask( void * pvParameters ); /* * Created by the connection listening task to handle a single connection. */ static void prvServerConnectionInstance( void * pvParameters ); /*-----------------------------------------------------------*/ /* Stores the stack size passed into vStartSimpleTCPServerTasks() so it can be * reused when the server listening task creates tasks to handle connections. */ static uint16_t usUsedStackSize = 0; /* Create task stack and buffers for use in the Listening and Server connection tasks */ static StaticTask_t listenerTaskBuffer; static StackType_t listenerTaskStack[ PTHREAD_STACK_MIN ]; static StaticTask_t echoServerTaskBuffer; static StackType_t echoServerTaskStack[ PTHREAD_STACK_MIN ]; /*-----------------------------------------------------------*/ void vStartSimpleTCPServerTasks( uint16_t usStackSize, UBaseType_t uxPriority ) { /* Create the TCP echo server. */ xTaskCreateStatic( prvConnectionListeningTask, "ServerListener", PTHREAD_STACK_MIN, NULL, uxPriority + 1, listenerTaskStack, &listenerTaskBuffer ); /* Remember the requested stack size so it can be re-used by the server * listening task when it creates tasks to handle connections. */ usUsedStackSize = usStackSize; } /*-----------------------------------------------------------*/ static void prvConnectionListeningTask( void * pvParameters ) { struct freertos_sockaddr xClient, xBindAddress; Socket_t xListeningSocket, xConnectedSocket; socklen_t xSize = sizeof( xClient ); static const TickType_t xReceiveTimeOut = portMAX_DELAY; const BaseType_t xBacklog = 20; #if ( ipconfigUSE_TCP_WIN == 1 ) WinProperties_t xWinProps; /* Fill in the buffer and window sizes that will be used by the socket. */ xWinProps.lTxBufSize = ipconfigTCP_TX_BUFFER_LENGTH; xWinProps.lTxWinSize = configECHO_SERVER_TX_WINDOW_SIZE; xWinProps.lRxBufSize = ipconfigTCP_RX_BUFFER_LENGTH; xWinProps.lRxWinSize = configECHO_SERVER_RX_WINDOW_SIZE; #endif /* ipconfigUSE_TCP_WIN */ /* Just to prevent compiler warnings. */ ( void ) pvParameters; /* Attempt to open the socket. */ xListeningSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP ); configASSERT( xListeningSocket != FREERTOS_INVALID_SOCKET ); /* Set a time out so accept() will just wait for a connection. */ FreeRTOS_setsockopt( xListeningSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) ); /* Set the window and buffer sizes. */ #if ( ipconfigUSE_TCP_WIN == 1 ) { FreeRTOS_setsockopt( xListeningSocket, 0, FREERTOS_SO_WIN_PROPERTIES, ( void * ) &xWinProps, sizeof( xWinProps ) ); } #endif /* ipconfigUSE_TCP_WIN */ /* Bind the socket to the port that the client task will send to, then * listen for incoming connections. */ xBindAddress.sin_port = tcpechoPORT_NUMBER; xBindAddress.sin_port = FreeRTOS_htons( xBindAddress.sin_port ); FreeRTOS_bind( xListeningSocket, &xBindAddress, sizeof( xBindAddress ) ); FreeRTOS_listen( xListeningSocket, xBacklog ); for( ;; ) { /* Wait for a client to connect. */ xConnectedSocket = FreeRTOS_accept( xListeningSocket, &xClient, &xSize ); configASSERT( xConnectedSocket != FREERTOS_INVALID_SOCKET ); /* Spawn a task to handle the connection. */ xTaskCreateStatic( prvServerConnectionInstance, "EchoServer", PTHREAD_STACK_MIN, ( void * ) xConnectedSocket, tskIDLE_PRIORITY, echoServerTaskStack, &echoServerTaskBuffer ); } } /*-----------------------------------------------------------*/ static void prvServerConnectionInstance( void * pvParameters ) { int32_t lBytes, lSent, lTotalSent; Socket_t xConnectedSocket; static const TickType_t xReceiveTimeOut = pdMS_TO_TICKS( 5000 ); static const TickType_t xSendTimeOut = pdMS_TO_TICKS( 5000 ); TickType_t xTimeOnShutdown; uint8_t * pucRxBuffer; xConnectedSocket = ( Socket_t ) pvParameters; /* Attempt to create the buffer used to receive the string to be echoed * back. This could be avoided using a zero copy interface that just returned * the same buffer. */ pucRxBuffer = ( uint8_t * ) pvPortMalloc( ipconfigTCP_MSS ); if( pucRxBuffer != NULL ) { FreeRTOS_setsockopt( xConnectedSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) ); FreeRTOS_setsockopt( xConnectedSocket, 0, FREERTOS_SO_SNDTIMEO, &xSendTimeOut, sizeof( xReceiveTimeOut ) ); for( ;; ) { /* Zero out the receive array so there is NULL at the end of the string * when it is printed out. */ memset( pucRxBuffer, 0x00, ipconfigTCP_MSS ); /* Receive data on the socket. */ lBytes = FreeRTOS_recv( xConnectedSocket, pucRxBuffer, ipconfigTCP_MSS, 0 ); /* If data was received, echo it back. */ if( lBytes >= 0 ) { lSent = 0; lTotalSent = 0; /* Call send() until all the data has been sent. */ while( ( lSent >= 0 ) && ( lTotalSent < lBytes ) ) { lSent = FreeRTOS_send( xConnectedSocket, pucRxBuffer, lBytes - lTotalSent, 0 ); lTotalSent += lSent; } if( lSent < 0 ) { /* Socket closed? */ break; } } else { /* Socket closed? */ break; } } } /* Initiate a shutdown in case it has not already been initiated. */ FreeRTOS_shutdown( xConnectedSocket, FREERTOS_SHUT_RDWR ); /* Wait for the shutdown to take effect, indicated by FreeRTOS_recv() * returning an error. */ xTimeOnShutdown = xTaskGetTickCount(); do { if( FreeRTOS_recv( xConnectedSocket, pucRxBuffer, ipconfigTCP_MSS, 0 ) < 0 ) { break; } } while( ( xTaskGetTickCount() - xTimeOnShutdown ) < tcpechoSHUTDOWN_DELAY ); /* Finished with the socket, buffer, the task. */ vPortFree( pucRxBuffer ); FreeRTOS_closesocket( xConnectedSocket ); vTaskDelete( NULL ); } /*-----------------------------------------------------------*/ /* The whole file is excluded if TCP is not compiled in. */ #endif /* ipconfigUSE_TCP */