1 /* 2 * FreeRTOS V202212.00 3 * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 * this software and associated documentation files (the "Software"), to deal in 7 * the Software without restriction, including without limitation the rights to 8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 * the Software, and to permit persons to whom the Software is furnished to do so, 10 * subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included in all 13 * copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * https://www.FreeRTOS.org 23 * https://github.com/FreeRTOS 24 * 25 */ 26 27 /* 28 * http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading 29 * the FAQ page "My application does not run, what could be wrong?". Have you 30 * defined configASSERT()? 31 * 32 * http://www.FreeRTOS.org/support - In return for receiving this top quality 33 * embedded software for free we request you assist our global community by 34 * participating in the support forum. 35 * 36 * http://www.FreeRTOS.org/training - Investing in training allows your team to 37 * be as productive as possible as early as possible. Now you can receive 38 * FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers 39 * Ltd, and the world's leading authority on the world's leading RTOS. 40 * 41 * http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, 42 * including FreeRTOS+Trace - an indispensable productivity tool, a DOS 43 * compatible FAT file system, and our tiny thread aware UDP/IP stack. 44 * 45 * http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. 46 * Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. 47 * 48 * http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High 49 * Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS 50 * licenses offer ticketed support, indemnification and commercial middleware. 51 * 52 * http://www.SafeRTOS.com - High Integrity Systems also provide a safety 53 * engineered and independently SIL3 certified version for use in safety and 54 * mission critical applications that require provable dependability. 55 * 56 */ 57 58 /* 59 * FreeRTOS tasks are used with FreeRTOS+TCP to create a TCP echo server on the 60 * standard echo port number (7). 61 * 62 * See the following web page for essential demo usage and configuration 63 * details: 64 * https://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_Echo_Server.html 65 */ 66 67 /* Standard includes. */ 68 #include <stdint.h> 69 #include <stdio.h> 70 #include <limits.h> 71 72 /* FreeRTOS includes. */ 73 #include "FreeRTOS.h" 74 #include "task.h" 75 #include "semphr.h" 76 77 /* FreeRTOS+TCP includes. */ 78 #include "FreeRTOS_IP.h" 79 #include "FreeRTOS_Sockets.h" 80 81 /* Remove the whole file if FreeRTOSIPConfig.h is set to exclude TCP. */ 82 #if ( ipconfigUSE_TCP == 1 ) 83 84 /* The maximum time to wait for a closing socket to close. */ 85 #define tcpechoSHUTDOWN_DELAY ( pdMS_TO_TICKS( 5000 ) ) 86 87 /* The standard echo port number. */ 88 #define tcpechoPORT_NUMBER 7 89 90 /* If ipconfigUSE_TCP_WIN is 1 then the Tx sockets will use a buffer size set by 91 * ipconfigTCP_TX_BUFFER_LENGTH, and the Tx window size will be 92 * configECHO_SERVER_TX_WINDOW_SIZE times the buffer size. Note 93 * ipconfigTCP_TX_BUFFER_LENGTH is set in FreeRTOSIPConfig.h as it is a standard TCP/IP 94 * stack constant, whereas configECHO_SERVER_TX_WINDOW_SIZE is set in 95 * FreeRTOSConfig.h as it is a demo application constant. */ 96 #ifndef configECHO_SERVER_TX_WINDOW_SIZE 97 #define configECHO_SERVER_TX_WINDOW_SIZE 2 98 #endif 99 100 /* If ipconfigUSE_TCP_WIN is 1 then the Rx sockets will use a buffer size set by 101 * ipconfigTCP_RX_BUFFER_LENGTH, and the Rx window size will be 102 * configECHO_SERVER_RX_WINDOW_SIZE times the buffer size. Note 103 * ipconfigTCP_RX_BUFFER_LENGTH is set in FreeRTOSIPConfig.h as it is a standard TCP/IP 104 * stack constant, whereas configECHO_SERVER_RX_WINDOW_SIZE is set in 105 * FreeRTOSConfig.h as it is a demo application constant. */ 106 #ifndef configECHO_SERVER_RX_WINDOW_SIZE 107 #define configECHO_SERVER_RX_WINDOW_SIZE 2 108 #endif 109 110 /*-----------------------------------------------------------*/ 111 112 /* 113 * Uses FreeRTOS+TCP to listen for incoming echo connections, creating a task 114 * to handle each connection. 115 */ 116 static void prvConnectionListeningTask( void * pvParameters ); 117 118 /* 119 * Created by the connection listening task to handle a single connection. 120 */ 121 static void prvServerConnectionInstance( void * pvParameters ); 122 123 /*-----------------------------------------------------------*/ 124 125 /* Stores the stack size passed into vStartSimpleTCPServerTasks() so it can be 126 * reused when the server listening task creates tasks to handle connections. */ 127 static uint16_t usUsedStackSize = 0; 128 129 /* Create task stack and buffers for use in the Listening and Server connection tasks */ 130 static StaticTask_t listenerTaskBuffer; 131 static StackType_t listenerTaskStack[ PTHREAD_STACK_MIN ]; 132 133 static StaticTask_t echoServerTaskBuffer; 134 static StackType_t echoServerTaskStack[ PTHREAD_STACK_MIN ]; 135 136 /*-----------------------------------------------------------*/ 137 vStartSimpleTCPServerTasks(uint16_t usStackSize,UBaseType_t uxPriority)138 void vStartSimpleTCPServerTasks( uint16_t usStackSize, 139 UBaseType_t uxPriority ) 140 { 141 /* Create the TCP echo server. */ 142 xTaskCreateStatic( prvConnectionListeningTask, 143 "ServerListener", 144 PTHREAD_STACK_MIN, 145 NULL, 146 uxPriority + 1, 147 listenerTaskStack, 148 &listenerTaskBuffer ); 149 150 /* Remember the requested stack size so it can be re-used by the server 151 * listening task when it creates tasks to handle connections. */ 152 usUsedStackSize = usStackSize; 153 } 154 /*-----------------------------------------------------------*/ 155 prvConnectionListeningTask(void * pvParameters)156 static void prvConnectionListeningTask( void * pvParameters ) 157 { 158 struct freertos_sockaddr xClient, xBindAddress; 159 Socket_t xListeningSocket, xConnectedSocket; 160 socklen_t xSize = sizeof( xClient ); 161 static const TickType_t xReceiveTimeOut = portMAX_DELAY; 162 const BaseType_t xBacklog = 20; 163 164 #if ( ipconfigUSE_TCP_WIN == 1 ) 165 WinProperties_t xWinProps; 166 167 /* Fill in the buffer and window sizes that will be used by the socket. */ 168 xWinProps.lTxBufSize = ipconfigTCP_TX_BUFFER_LENGTH; 169 xWinProps.lTxWinSize = configECHO_SERVER_TX_WINDOW_SIZE; 170 xWinProps.lRxBufSize = ipconfigTCP_RX_BUFFER_LENGTH; 171 xWinProps.lRxWinSize = configECHO_SERVER_RX_WINDOW_SIZE; 172 #endif /* ipconfigUSE_TCP_WIN */ 173 174 /* Just to prevent compiler warnings. */ 175 ( void ) pvParameters; 176 177 /* Attempt to open the socket. */ 178 xListeningSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP ); 179 configASSERT( xListeningSocket != FREERTOS_INVALID_SOCKET ); 180 181 /* Set a time out so accept() will just wait for a connection. */ 182 FreeRTOS_setsockopt( xListeningSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) ); 183 184 /* Set the window and buffer sizes. */ 185 #if ( ipconfigUSE_TCP_WIN == 1 ) 186 { 187 FreeRTOS_setsockopt( xListeningSocket, 0, FREERTOS_SO_WIN_PROPERTIES, ( void * ) &xWinProps, sizeof( xWinProps ) ); 188 } 189 #endif /* ipconfigUSE_TCP_WIN */ 190 191 /* Bind the socket to the port that the client task will send to, then 192 * listen for incoming connections. */ 193 xBindAddress.sin_port = tcpechoPORT_NUMBER; 194 xBindAddress.sin_port = FreeRTOS_htons( xBindAddress.sin_port ); 195 xBindAddress.sin_family = FREERTOS_AF_INET; 196 FreeRTOS_bind( xListeningSocket, &xBindAddress, sizeof( xBindAddress ) ); 197 FreeRTOS_listen( xListeningSocket, xBacklog ); 198 199 for( ; ; ) 200 { 201 /* Wait for a client to connect. */ 202 xConnectedSocket = FreeRTOS_accept( xListeningSocket, &xClient, &xSize ); 203 configASSERT( xConnectedSocket != FREERTOS_INVALID_SOCKET ); 204 205 /* Spawn a task to handle the connection. */ 206 xTaskCreateStatic( prvServerConnectionInstance, 207 "EchoServer", 208 PTHREAD_STACK_MIN, 209 ( void * ) xConnectedSocket, 210 tskIDLE_PRIORITY, 211 echoServerTaskStack, 212 &echoServerTaskBuffer ); 213 } 214 } 215 /*-----------------------------------------------------------*/ 216 prvServerConnectionInstance(void * pvParameters)217 static void prvServerConnectionInstance( void * pvParameters ) 218 { 219 int32_t lBytes, lSent, lTotalSent; 220 Socket_t xConnectedSocket; 221 static const TickType_t xReceiveTimeOut = pdMS_TO_TICKS( 5000 ); 222 static const TickType_t xSendTimeOut = pdMS_TO_TICKS( 5000 ); 223 TickType_t xTimeOnShutdown; 224 uint8_t * pucRxBuffer; 225 226 xConnectedSocket = ( Socket_t ) pvParameters; 227 228 /* Attempt to create the buffer used to receive the string to be echoed 229 * back. This could be avoided using a zero copy interface that just returned 230 * the same buffer. */ 231 pucRxBuffer = ( uint8_t * ) pvPortMalloc( ipconfigTCP_MSS ); 232 233 if( pucRxBuffer != NULL ) 234 { 235 FreeRTOS_setsockopt( xConnectedSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) ); 236 FreeRTOS_setsockopt( xConnectedSocket, 0, FREERTOS_SO_SNDTIMEO, &xSendTimeOut, sizeof( xReceiveTimeOut ) ); 237 238 for( ; ; ) 239 { 240 /* Zero out the receive array so there is NULL at the end of the string 241 * when it is printed out. */ 242 memset( pucRxBuffer, 0x00, ipconfigTCP_MSS ); 243 244 /* Receive data on the socket. */ 245 lBytes = FreeRTOS_recv( xConnectedSocket, pucRxBuffer, ipconfigTCP_MSS, 0 ); 246 247 /* If data was received, echo it back. */ 248 if( lBytes >= 0 ) 249 { 250 lSent = 0; 251 lTotalSent = 0; 252 253 /* Call send() until all the data has been sent. */ 254 while( ( lSent >= 0 ) && ( lTotalSent < lBytes ) ) 255 { 256 lSent = FreeRTOS_send( xConnectedSocket, pucRxBuffer, lBytes - lTotalSent, 0 ); 257 lTotalSent += lSent; 258 } 259 260 if( lSent < 0 ) 261 { 262 /* Socket closed? */ 263 break; 264 } 265 } 266 else 267 { 268 /* Socket closed? */ 269 break; 270 } 271 } 272 } 273 274 /* Initiate a shutdown in case it has not already been initiated. */ 275 FreeRTOS_shutdown( xConnectedSocket, FREERTOS_SHUT_RDWR ); 276 277 /* Wait for the shutdown to take effect, indicated by FreeRTOS_recv() 278 * returning an error. */ 279 xTimeOnShutdown = xTaskGetTickCount(); 280 281 do 282 { 283 if( FreeRTOS_recv( xConnectedSocket, pucRxBuffer, ipconfigTCP_MSS, 0 ) < 0 ) 284 { 285 break; 286 } 287 } while( ( xTaskGetTickCount() - xTimeOnShutdown ) < tcpechoSHUTDOWN_DELAY ); 288 289 /* Finished with the socket, buffer, the task. */ 290 vPortFree( pucRxBuffer ); 291 FreeRTOS_closesocket( xConnectedSocket ); 292 293 vTaskDelete( NULL ); 294 } 295 /*-----------------------------------------------------------*/ 296 297 /* The whole file is excluded if TCP is not compiled in. */ 298 #endif /* ipconfigUSE_TCP */ 299