You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
FreeRTOS/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Echo_Posix/SimpleTCPEchoServer.c

298 lines
12 KiB
C

/*
* 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 <stdint.h>
#include <stdio.h>
#include <limits.h>
/* 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 */