/* * Amazon FreeRTOS V1.4.7 * 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 */ /* * FreeRTOS tasks are used with FreeRTOS+TCP to create a TCP echo server. Echo * clients are also created, but the echo clients use Windows threads (as * opposed to FreeRTOS tasks) and use the Windows TCP library (Winsocks). This * creates a communication between the FreeRTOS+TCP TCP/IP stack and the Windows * TCP/IP stack. * * See the following web page for essential demo usage and configuration * details: * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/examples_FreeRTOS_simulator.html */ /* Standard includes. */ #include #include /* FreeRTOS includes. */ #include "FreeRTOS.h" #include "task.h" /* FreeRTOS+TCP includes. */ #include "FreeRTOS_IP.h" #include "FreeRTOS_Sockets.h" /* Demo specific includes */ #include "aws_simple_tcp_echo_server.h" #include "aws_demo_config.h" /* Specifies the size of the data sent to the server in MSS units. */ #define tcpechoBUFFER_SIZE_MULTIPLIER 3 /* The maximum time to wait for a closing socket to close. */ #define tcpechoSHUTDOWN_DELAY ( pdMS_TO_TICKS( 5000 ) ) /* The standard echo port number. */ #ifdef configTCP_ECHO_CLIENT_PORT #define tcpechoPORT_NUMBER configTCP_ECHO_CLIENT_PORT #else #define tcpechoPORT_NUMBER 7 #endif /* The size of the Rx and Tx buffers. */ #define tcpechoBUFFER_SIZE ( ipconfigTCP_MSS * tcpechoBUFFER_SIZE_MULTIPLIER ) /*-----------------------------------------------------------*/ /* * 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; /* Used for error reporting. */ static uint32_t ulConnectionCount = 0; /*-----------------------------------------------------------*/ void vStartSimpleTCPServerTasks( void ) { /* Create the TCP echo server. The echo server uses FreeRTOS+TCP through * the spoofed IP and MAC address. The WinSock client tasks are created from * inside the listening task. */ xTaskCreate( prvConnectionListeningTask, "ServerListener", democonfigTCP_ECHO_SERVER_TASK_STACK_SIZE, NULL, democonfigTCP_ECHO_SERVER_TASK_PRIORITY + 1, NULL ); /* Remember the requested stack size so it can be re-used by the server * listening task when it creates tasks to handle connections. */ usUsedStackSize = democonfigTCP_ECHO_SERVER_TASK_STACK_SIZE; } /*-----------------------------------------------------------*/ 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; WinProperties_t xWinProps; /* 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 ) ); /* Fill in the buffer and window sizes that will be used by the socket. */ xWinProps.lTxBufSize = 6 * ipconfigTCP_MSS; xWinProps.lTxWinSize = 3; xWinProps.lRxBufSize = 6 * ipconfigTCP_MSS; xWinProps.lRxWinSize = 3; /* Set the window and buffer sizes. */ FreeRTOS_setsockopt( xListeningSocket, 0, FREERTOS_SO_WIN_PROPERTIES, ( void * ) &xWinProps, sizeof( xWinProps ) ); /* 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. */ xTaskCreate( prvServerConnectionInstance, "EchoServer", usUsedStackSize, ( void * ) xConnectedSocket, tskIDLE_PRIORITY, NULL ); } } /*-----------------------------------------------------------*/ static void prvServerConnectionInstance( void * pvParameters ) { int32_t lBytes, lSent, lTotalSent; uint8_t cReceivedString[ ipconfigTCP_MSS ]; /* Big stack usage, for Windows port only! */ Socket_t xConnectedSocket; static const TickType_t xReceiveTimeOut = pdMS_TO_TICKS( 5000 ); static const TickType_t xSendTimeOut = pdMS_TO_TICKS( 5000 ); TickType_t xTimeOnShutdown; ulConnectionCount++; xConnectedSocket = ( Socket_t ) pvParameters; 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( cReceivedString, 0x00, sizeof( cReceivedString ) ); /* Receive data on the socket. */ lBytes = FreeRTOS_recv( xConnectedSocket, cReceivedString, sizeof( cReceivedString ), 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, cReceivedString, 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, cReceivedString, ipconfigTCP_MSS, 0 ) < 0 ) { break; } } while( ( xTaskGetTickCount() - xTimeOnShutdown ) < tcpechoSHUTDOWN_DELAY ); /* Finished with the socket and the task. */ FreeRTOS_closesocket( xConnectedSocket ); vTaskDelete( NULL ); } /*-----------------------------------------------------------*/ BaseType_t xAreTCPEchoServersStillRunning( void ) { static uint32_t ulLastConnectionCount = 0; BaseType_t xReturn = pdPASS; if( ulConnectionCount == ulLastConnectionCount ) { xReturn = pdFAIL; } else { ulLastConnectionCount = ulConnectionCount; } return xReturn; } /*-----------------------------------------------------------*/