/* Standard includes. */ #include /*#include */ /* FreeRTOS includes. */ #include "FreeRTOS.h" #include "task.h" #include "semphr.h" /* FreeRTOS+TCP includes. */ #include "FreeRTOS_IP.h" #include "FreeRTOS_IP_Private.h" #include "FreeRTOS_Sockets.h" #include "FreeRTOS_Stream_Buffer.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 #ifndef configECHO_SERVER_TX_WINDOW_SIZE #define configECHO_SERVER_TX_WINDOW_SIZE 2 #endif #ifndef configECHO_SERVER_RX_WINDOW_SIZE #define configECHO_SERVER_RX_WINDOW_SIZE 2 #endif void FreeRTOS_ReleaseTCPPayload( void const * pvBuffer, Socket_t xSocket, BaseType_t xByteCount ); /*-----------------------------------------------------------*/ /* * Uses FreeRTOS+TCP to listen for incoming echo connections, creating a socket * to handle each connection. */ static void prvConnectionListeningTask( void * pvParameters ); /*-----------------------------------------------------------*/ void vStartSimpleTCPServerTasks( uint16_t usStackSize, UBaseType_t uxPriority ); void vStartSimpleTCPServerTasks( uint16_t usStackSize, UBaseType_t uxPriority ) { /* Create the TCP echo server. */ xTaskCreate( prvConnectionListeningTask, "TcpEchoServer", usStackSize, NULL, uxPriority, NULL ); } /*-----------------------------------------------------------*/ static Socket_t xSockets[ 2 ]; static const BaseType_t xBacklog = sizeof( xSockets ) / sizeof( xSockets[ 0 ] ); static void close_socket( SocketSet_t xSocketSet, BaseType_t xInst ) { FreeRTOS_FD_CLR( xSockets[ xInst ], xSocketSet, eSELECT_ALL ); FreeRTOS_closesocket( xSockets[ xInst ] ); xSockets[ xInst ] = NULL; } static void prvConnectionListeningTask( void * pvParameters ) { /*Socket_t xSockets[2]; */ /*static const BaseType_t xBacklog = sizeof( xSockets ) / sizeof( xSockets[0] ); */ struct freertos_sockaddr xClient, xBindAddress; socklen_t xClientSize = sizeof( xClient ); Socket_t xListeningSocket, xConnectedSocket; SocketSet_t xSocketSet; static const TickType_t xReceiveTimeOut = 0; static const TickType_t xSendTimeOut = pdMS_TO_TICKS( 5000 ); BaseType_t xResult; BaseType_t xInst; uint8_t * pucRxBuffer; #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; /* Initialize the list of client sockets. */ for( xInst = 0; xInst < xBacklog; xInst++ ) { xSockets[ xInst ] = NULL; } /* Create the set of sockets that will be passed into FreeRTOS_select(). */ xSocketSet = FreeRTOS_CreateSocketSet(); configASSERT( xSocketSet != NULL ); /* Attempt to open the socket. */ xListeningSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP ); configASSERT( xListeningSocket != FREERTOS_INVALID_SOCKET ); /* Set a 0 time out so accept() will not 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 ); /* Only the READ event can unblock a call to select(). */ FreeRTOS_FD_SET( xListeningSocket, xSocketSet, eSELECT_READ ); for( ; ; ) { /* Wait for any event within the socket set. */ xResult = FreeRTOS_select( xSocketSet, portMAX_DELAY ); if( xResult != 0 ) { /* The return value should never be zero because FreeRTOS_select() was called * with an indefinite delay (assuming INCLUDE_vTaskSuspend is set to 1). * Now check each socket which belongs to the set if it had an event. */ for( xInst = 0; xInst < xBacklog; xInst++ ) { if( xSockets[ xInst ] != NULL ) { EventBits_t uxBits = FreeRTOS_FD_ISSET( xSockets[ xInst ], xSocketSet ); if( ( uxBits & eSELECT_EXCEPT ) != 0U ) { close_socket( xSocketSet, xInst ); } else { while( ( uxBits & eSELECT_READ ) != 0U ) { BaseType_t lBytes; /* Receive data on the socket. */ #define USE_ZERO_COPY 0 #if USE_ZERO_COPY lBytes = FreeRTOS_recv( xSockets[ xInst ], &( pucRxBuffer ), 0, FREERTOS_ZERO_COPY ); #else uint8_t ucRxBuffer[ 512 ]; pucRxBuffer = ucRxBuffer; lBytes = FreeRTOS_recv( xSockets[ xInst ], pucRxBuffer, sizeof( ucRxBuffer ), 0 ); #endif /* If data was received, echo it back. */ /* _HT_ when "lBytes<= 0", there is no eed to call FreeRTOS_ReleaseTCPPayload(). */ if( lBytes > 0 ) { BaseType_t lTotalSent = 0; BaseType_t lSent = 0; /* Call send() until all the data has been sent. */ while( lTotalSent < lBytes ) { lSent = FreeRTOS_send( xSockets[ xInst ], pucRxBuffer + lTotalSent, lBytes - lTotalSent, 0 ); if( lSent <= 0 ) { break; } lTotalSent += lSent; } #if USE_ZERO_COPY /* Release the data now that it was consumed. */ FreeRTOS_ReleaseTCPPayload( pucRxBuffer, xSockets[ xInst ], lBytes ); #endif if( ( lSent < 0 ) && ( lSent != -pdFREERTOS_ERRNO_EAGAIN ) ) { /* lSend() returned an error, close the socket. */ close_socket( xSocketSet, xInst ); } } else if( ( lBytes < 0 ) && ( lBytes != -pdFREERTOS_ERRNO_EAGAIN ) ) { /* _HT_ * recv() returned an error, which might me a memory-allocation error, * a protocol error, or just a disconnection. * Chances will be small because you would expect to receive * a eSELECT_EXCEPT event. * I recommend to handle this */ close_socket( xSocketSet, xInst ); } if( lBytes <= 0 ) { /* Clear the READ bit. */ uxBits &= ~( eSELECT_READ ); } } /* while( ( uxBits & eSELECT_READ ) != 0U ) */ } /* if( ( uxBits & eSELECT_EXCEPT ) != 0U ) */ } /* if( xSockets[xInst] != NULL ) */ } /* for( xInst = 0; xInst < xBacklog; xInst++ ) */ if( FreeRTOS_FD_ISSET( xListeningSocket, xSocketSet ) != 0U ) { /* Wait for a client to connect. */ xConnectedSocket = FreeRTOS_accept( xListeningSocket, &xClient, &xClientSize ); configASSERT( xConnectedSocket != FREERTOS_INVALID_SOCKET ); for( xInst = 0; xInst < xBacklog; xInst++ ) { if( xSockets[ xInst ] == NULL ) { break; } } if( xInst < xBacklog ) { xSockets[ xInst ] = xConnectedSocket; FreeRTOS_FD_SET( xConnectedSocket, xSocketSet, eSELECT_READ | eSELECT_EXCEPT ); FreeRTOS_setsockopt( xConnectedSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) ); FreeRTOS_setsockopt( xConnectedSocket, 0, FREERTOS_SO_SNDTIMEO, &xSendTimeOut, sizeof( xSendTimeOut ) ); } else { /* This shouldn't happen. */ FreeRTOS_closesocket( xConnectedSocket ); } } } /* if( xResult != 0 ) */ } /* for( ; ; ) */ } /*-----------------------------------------------------------*/ void FreeRTOS_ReleaseTCPPayload( void const * pvBuffer, Socket_t xSocket, BaseType_t xByteCount ) { BaseType_t xByteCountReleased; uint8_t * pucData; size_t uxBytesAvailable = uxStreamBufferGetPtr( xSocket->u.xTCP.rxStream, &( pucData ) ); /* Make sure the pointer is correct. */ configASSERT( pucData == ( uint8_t * ) pvBuffer ); /* Avoid releasing more bytes than available. */ configASSERT( uxBytesAvailable >= ( size_t ) xByteCount ); /* Call recv with NULL pointer to advance the circular buffer. */ xByteCountReleased = FreeRTOS_recv( xSocket, NULL, xByteCount, FREERTOS_MSG_DONTWAIT ); configASSERT( xByteCountReleased == xByteCount ); } /*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/ /* The whole file is excluded if TCP is not compiled in. */ #endif /* ipconfigUSE_TCP */