From: rtel Date: Wed, 22 Aug 2018 21:29:21 +0000 (+0000) Subject: Fix some build issues in older kernel demo projects. X-Git-Tag: V10.1.0~2 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=f99d299ee374d53b2de76a8c920812ef10859b48;p=freertos Fix some build issues in older kernel demo projects. Update to V2.0.7 of the TCP/IP stack: + Multiple security improvements and fixes in packet parsing routines, DNS caching, and TCP sequence number and ID generation. + Disable NBNS and LLMNR by default. + Add TCP hang protection by default. We thank Ori Karliner of Zimperium zLabs Team for reporting these issues. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@2563 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- diff --git a/FreeRTOS-Plus/Demo/Common/Demo_IP_Protocols/Common/FreeRTOS_TCP_server.c b/FreeRTOS-Plus/Demo/Common/Demo_IP_Protocols/Common/FreeRTOS_TCP_server.c new file mode 100644 index 000000000..3b9f8fb2f --- /dev/null +++ b/FreeRTOS-Plus/Demo/Common/Demo_IP_Protocols/Common/FreeRTOS_TCP_server.c @@ -0,0 +1,353 @@ +/* + * FreeRTOS+TCP V2.0.3 + * 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 + */ + + +/* Standard includes. */ +#include +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_TCP_server.h" +#include "FreeRTOS_server_private.h" + +/* Remove the entire file if TCP is not being used. */ +#if( ipconfigUSE_TCP == 1 ) && ( ( ipconfigUSE_HTTP == 1 ) || ( ipconfigUSE_FTP == 1 ) ) + +#if !defined( ARRAY_SIZE ) + #define ARRAY_SIZE(x) ( BaseType_t ) (sizeof( x ) / sizeof( x )[ 0 ] ) +#endif + + +static void prvReceiveNewClient( TCPServer_t *pxServer, BaseType_t xIndex, Socket_t xNexSocket ); +static char *strnew( const char *pcString ); +/* Remove slashes at the end of a path. */ +static void prvRemoveSlash( char *pcDir ); + +TCPServer_t *FreeRTOS_CreateTCPServer( const struct xSERVER_CONFIG *pxConfigs, BaseType_t xCount ) +{ +TCPServer_t *pxServer; +SocketSet_t xSocketSet; + + /* Create a new server. + xPort / xPortAlt : Make the service available on 1 or 2 public port numbers. */ + xSocketSet = FreeRTOS_CreateSocketSet(); + + if( xSocketSet != NULL ) + { + BaseType_t xSize; + + xSize = sizeof( *pxServer ) - sizeof( pxServer->xServers ) + xCount * sizeof( pxServer->xServers[ 0 ] ); + + pxServer = ( TCPServer_t * ) pvPortMallocLarge( xSize ); + if( pxServer != NULL ) + { + struct freertos_sockaddr xAddress; + BaseType_t xNoTimeout = 0; + BaseType_t xIndex; + + memset( pxServer, '\0', xSize ); + pxServer->xServerCount = xCount; + pxServer->xSocketSet = xSocketSet; + + for( xIndex = 0; xIndex < xCount; xIndex++ ) + { + BaseType_t xPortNumber = pxConfigs[ xIndex ].xPortNumber; + + if( xPortNumber > 0 ) + { + Socket_t xSocket; + + xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP ); + FreeRTOS_printf( ( "TCP socket on port %d\n", ( int )xPortNumber ) ); + + if( xSocket != FREERTOS_NO_SOCKET ) + { + xAddress.sin_addr = FreeRTOS_GetIPAddress(); // Single NIC, currently not used + xAddress.sin_port = FreeRTOS_htons( xPortNumber ); + + FreeRTOS_bind( xSocket, &xAddress, sizeof( xAddress ) ); + FreeRTOS_listen( xSocket, pxConfigs[ xIndex ].xBackLog ); + + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVTIMEO, ( void * ) &xNoTimeout, sizeof( BaseType_t ) ); + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, ( void * ) &xNoTimeout, sizeof( BaseType_t ) ); + + #if( ipconfigHTTP_RX_BUFSIZE > 0 ) + { + if( pxConfigs[ xIndex ].eType == eSERVER_HTTP ) + { + WinProperties_t xWinProps; + + memset( &xWinProps, '\0', sizeof( xWinProps ) ); + /* The parent socket itself won't get connected. The properties below + will be inherited by each new child socket. */ + xWinProps.lTxBufSize = ipconfigHTTP_TX_BUFSIZE; + xWinProps.lTxWinSize = ipconfigHTTP_TX_WINSIZE; + xWinProps.lRxBufSize = ipconfigHTTP_RX_BUFSIZE; + xWinProps.lRxWinSize = ipconfigHTTP_RX_WINSIZE; + + /* Set the window and buffer sizes. */ + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_WIN_PROPERTIES, ( void * ) &xWinProps, sizeof( xWinProps ) ); + } + } + #endif + + FreeRTOS_FD_SET( xSocket, xSocketSet, eSELECT_READ|eSELECT_EXCEPT ); + pxServer->xServers[ xIndex ].xSocket = xSocket; + pxServer->xServers[ xIndex ].eType = pxConfigs[ xIndex ].eType; + pxServer->xServers[ xIndex ].pcRootDir = strnew( pxConfigs[ xIndex ].pcRootDir ); + prvRemoveSlash( ( char * ) pxServer->xServers[ xIndex ].pcRootDir ); + } + } + } + } + else + { + /* Could not allocate the server, delete the socket set */ + FreeRTOS_DeleteSocketSet( xSocketSet ); + } + } + else + { + /* Could not create a socket set, return NULL */ + pxServer = NULL; + } + + return pxServer; +} +/*-----------------------------------------------------------*/ + +static void prvReceiveNewClient( TCPServer_t *pxServer, BaseType_t xIndex, Socket_t xNexSocket ) +{ +TCPClient_t *pxClient = NULL; +BaseType_t xSize = 0; +FTCPWorkFunction fWorkFunc = NULL; +FTCPDeleteFunction fDeleteFunc = NULL; +const char *pcType = "Unknown"; + + /*_RB_ Can the work and delete functions be part of the xSERVER_CONFIG structure + becomes generic, with no pre-processing required? */ + #if( ipconfigUSE_HTTP != 0 ) + { + if( pxServer->xServers[ xIndex ].eType == eSERVER_HTTP ) + { + xSize = sizeof( HTTPClient_t ); + fWorkFunc = xHTTPClientWork; + fDeleteFunc = vHTTPClientDelete; + pcType = "HTTP"; + } + } + #endif /* ipconfigUSE_HTTP != 0 */ + + #if( ipconfigUSE_FTP != 0 ) + { + if( pxServer->xServers[ xIndex ].eType == eSERVER_FTP ) + { + xSize = sizeof( FTPClient_t ); + fWorkFunc = xFTPClientWork; + fDeleteFunc = vFTPClientDelete; + pcType = "FTP"; + } + } + #endif /* ipconfigUSE_FTP != 0 */ + + /* Malloc enough space for a new HTTP-client */ + if( xSize ) + { + pxClient = ( TCPClient_t* ) pvPortMallocLarge( xSize ); + } + + if( pxClient != NULL ) + { + memset( pxClient, '\0', xSize ); + + /* Put the new client in front of the list. */ + pxClient->eType = pxServer->xServers[ xIndex ].eType; + pxClient->pcRootDir = pxServer->xServers[ xIndex ].pcRootDir; + pxClient->pxParent = pxServer; + pxClient->xSocket = xNexSocket; + pxClient->pxNextClient = pxServer->pxClients; + pxClient->fWorkFunction = fWorkFunc; + pxClient->fDeleteFunction = fDeleteFunc; + pxServer->pxClients = pxClient; + + FreeRTOS_FD_SET( xNexSocket, pxServer->xSocketSet, eSELECT_READ|eSELECT_EXCEPT ); + } + else + { + pcType = "closed"; + FreeRTOS_closesocket( xNexSocket ); + } + { + struct freertos_sockaddr xRemoteAddress; + FreeRTOS_GetRemoteAddress( pxClient->xSocket, &xRemoteAddress ); + FreeRTOS_printf( ( "TPC-server: new %s client %xip\n", pcType, (unsigned)FreeRTOS_ntohl( xRemoteAddress.sin_addr ) ) ); + } + + /* Remove compiler warnings in case FreeRTOS_printf() is not used. */ + ( void ) pcType; +} +/*-----------------------------------------------------------*/ + +void FreeRTOS_TCPServerWork( TCPServer_t *pxServer, TickType_t xBlockingTime ) +{ +TCPClient_t **ppxClient; +BaseType_t xIndex; +BaseType_t xRc; + + /* Let the server do one working cycle */ + xRc = FreeRTOS_select( pxServer->xSocketSet, xBlockingTime ); + + if( xRc != 0 ) + { + for( xIndex = 0; xIndex < pxServer->xServerCount; xIndex++ ) + { + struct freertos_sockaddr xAddress; + Socket_t xNexSocket; + socklen_t xSocketLength; + + if( pxServer->xServers[ xIndex ].xSocket == FREERTOS_NO_SOCKET ) + { + continue; + } + + xSocketLength = sizeof( xAddress ); + xNexSocket = FreeRTOS_accept( pxServer->xServers[ xIndex ].xSocket, &xAddress, &xSocketLength); + + if( ( xNexSocket != FREERTOS_NO_SOCKET ) && ( xNexSocket != FREERTOS_INVALID_SOCKET ) ) + { + prvReceiveNewClient( pxServer, xIndex, xNexSocket ); + } + } + } + + ppxClient = &pxServer->pxClients; + + while( ( * ppxClient ) != NULL ) + { + TCPClient_t *pxThis = *ppxClient; + + /* Almost C++ */ + xRc = pxThis->fWorkFunction( pxThis ); + + if (xRc < 0 ) + { + *ppxClient = pxThis->pxNextClient; + /* Close handles, resources */ + pxThis->fDeleteFunction( pxThis ); + /* Free the space */ + vPortFreeLarge( pxThis ); + } + else + { + ppxClient = &( pxThis->pxNextClient ); + } + } +} +/*-----------------------------------------------------------*/ + +static char *strnew( const char *pcString ) +{ +BaseType_t xLength; +char *pxBuffer; + + xLength = strlen( pcString ) + 1; + pxBuffer = ( char * ) pvPortMalloc( xLength ); + if( pxBuffer != NULL ) + { + memcpy( pxBuffer, pcString, xLength ); + } + + return pxBuffer; +} +/*-----------------------------------------------------------*/ + +static void prvRemoveSlash( char *pcDir ) +{ +BaseType_t xLength = strlen( pcDir ); + + while( ( xLength > 0 ) && ( pcDir[ xLength - 1 ] == '/' ) ) + { + pcDir[ --xLength ] = '\0'; + } +} +/*-----------------------------------------------------------*/ + +#if( ipconfigSUPPORT_SIGNALS != 0 ) + + /* FreeRTOS_TCPServerWork() calls select(). + The two functions below provide a possibility to interrupt + the call to select(). After the interruption, resume + by calling FreeRTOS_TCPServerWork() again. */ + BaseType_t FreeRTOS_TCPServerSignal( TCPServer_t *pxServer ) + { + BaseType_t xIndex; + BaseType_t xResult = pdFALSE; + for( xIndex = 0; xIndex < pxServer->xServerCount; xIndex++ ) + { + if( pxServer->xServers[ xIndex ].xSocket != FREERTOS_NO_SOCKET ) + { + FreeRTOS_SignalSocket( pxServer->xServers[ xIndex ].xSocket ); + xResult = pdTRUE; + break; + } + } + + return xResult; + } + +#endif /* ipconfigSUPPORT_SIGNALS */ +/*-----------------------------------------------------------*/ + +#if( ipconfigSUPPORT_SIGNALS != 0 ) + + /* Same as above: this function may be called from an ISR, + for instance a GPIO interrupt. */ + BaseType_t FreeRTOS_TCPServerSignalFromISR( TCPServer_t *pxServer, BaseType_t *pxHigherPriorityTaskWoken ) + { + BaseType_t xIndex; + BaseType_t xResult = pdFALSE; + for( xIndex = 0; xIndex < pxServer->xServerCount; xIndex++ ) + { + if( pxServer->xServers[ xIndex ].xSocket != FREERTOS_NO_SOCKET ) + { + FreeRTOS_SignalSocketFromISR( pxServer->xServers[ xIndex ].xSocket, pxHigherPriorityTaskWoken ); + xResult = pdTRUE; + break; + } + } + + return xResult; + } +#endif /* ipconfigSUPPORT_SIGNALS */ +/*-----------------------------------------------------------*/ + +#endif /* ( ipconfigUSE_TCP == 1 ) && ( ( ipconfigUSE_HTTP == 1 ) || ( ipconfigUSE_FTP == 1 ) ) */ diff --git a/FreeRTOS-Plus/Demo/Common/Demo_IP_Protocols/FTP/FreeRTOS_FTP_commands.c b/FreeRTOS-Plus/Demo/Common/Demo_IP_Protocols/FTP/FreeRTOS_FTP_commands.c new file mode 100644 index 000000000..b399f3648 --- /dev/null +++ b/FreeRTOS-Plus/Demo/Common/Demo_IP_Protocols/FTP/FreeRTOS_FTP_commands.c @@ -0,0 +1,74 @@ +/* + * FreeRTOS+TCP V2.0.3 + * 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 includes. */ +#include "FreeRTOS.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_FTP_commands.h" + +const FTPCommand_t xFTPCommands[ FTP_CMD_COUNT ] = +{ +/* cmdLen cmdName[7] cmdType checkLogin checkNullArg */ + { 4, "USER", ECMD_USER, pdFALSE, pdFALSE }, + { 4, "PASS", ECMD_PASS, pdFALSE, pdFALSE }, + { 4, "ACCT", ECMD_ACCT, pdTRUE, pdFALSE }, + { 3, "CWD", ECMD_CWD, pdTRUE, pdTRUE }, + { 4, "CDUP", ECMD_CDUP, pdTRUE, pdFALSE }, + { 4, "SMNT", ECMD_SMNT, pdTRUE, pdFALSE }, + { 4, "QUIT", ECMD_QUIT, pdTRUE, pdFALSE }, + { 4, "REIN", ECMD_REIN, pdTRUE, pdFALSE }, + { 4, "PORT", ECMD_PORT, pdTRUE, pdFALSE }, + { 4, "PASV", ECMD_PASV, pdTRUE, pdFALSE }, + { 4, "TYPE", ECMD_TYPE, pdTRUE, pdFALSE }, + { 4, "STRU", ECMD_STRU, pdTRUE, pdFALSE }, + { 4, "MODE", ECMD_MODE, pdTRUE, pdFALSE }, + { 4, "RETR", ECMD_RETR, pdTRUE, pdTRUE }, + { 4, "STOR", ECMD_STOR, pdTRUE, pdTRUE }, + { 4, "STOU", ECMD_STOU, pdTRUE, pdFALSE }, + { 4, "APPE", ECMD_APPE, pdTRUE, pdFALSE }, + { 4, "ALLO", ECMD_ALLO, pdTRUE, pdFALSE }, + { 4, "REST", ECMD_REST, pdTRUE, pdFALSE }, + { 4, "RNFR", ECMD_RNFR, pdTRUE, pdTRUE }, + { 4, "RNTO", ECMD_RNTO, pdTRUE, pdTRUE }, + { 4, "ABOR", ECMD_ABOR, pdTRUE, pdFALSE }, + { 4, "SIZE", ECMD_SIZE, pdTRUE, pdTRUE }, + { 4, "MDTM", ECMD_MDTM, pdTRUE, pdTRUE }, + { 4, "DELE", ECMD_DELE, pdTRUE, pdTRUE }, + { 3, "RMD", ECMD_RMD, pdTRUE, pdTRUE }, + { 3, "MKD", ECMD_MKD, pdTRUE, pdTRUE }, + { 3, "PWD", ECMD_PWD, pdTRUE, pdFALSE }, + { 4, "LIST", ECMD_LIST, pdTRUE, pdFALSE }, + { 4, "NLST", ECMD_NLST, pdTRUE, pdFALSE }, + { 4, "SITE", ECMD_SITE, pdTRUE, pdFALSE }, + { 4, "SYST", ECMD_SYST, pdFALSE, pdFALSE }, + { 4, "FEAT", ECMD_FEAT, pdFALSE, pdFALSE }, + { 4, "STAT", ECMD_STAT, pdTRUE, pdFALSE }, + { 4, "HELP", ECMD_HELP, pdFALSE, pdFALSE }, + { 4, "NOOP", ECMD_NOOP, pdFALSE, pdFALSE }, + { 4, "EMPT", ECMD_EMPTY, pdFALSE, pdFALSE }, + { 4, "CLOS", ECMD_CLOSE, pdTRUE, pdFALSE }, + { 4, "UNKN", ECMD_UNKNOWN, pdFALSE, pdFALSE }, +}; diff --git a/FreeRTOS-Plus/Demo/Common/Demo_IP_Protocols/FTP/FreeRTOS_FTP_server.c b/FreeRTOS-Plus/Demo/Common/Demo_IP_Protocols/FTP/FreeRTOS_FTP_server.c new file mode 100644 index 000000000..a2a6ba155 --- /dev/null +++ b/FreeRTOS-Plus/Demo/Common/Demo_IP_Protocols/FTP/FreeRTOS_FTP_server.c @@ -0,0 +1,2637 @@ +/* + * FreeRTOS+TCP V2.0.3 + * 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 + */ + +/* Standard includes. */ +#include +#include +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "portmacro.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_TCP_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_Stream_Buffer.h" + +/* FreeRTOS Protocol includes. */ +#include "FreeRTOS_FTP_commands.h" +#include "FreeRTOS_TCP_server.h" +#include "FreeRTOS_server_private.h" + +/* Remove the whole file if FTP is not supported. */ +#if( ipconfigUSE_FTP == 1 ) + +#ifndef HTTP_SERVER_BACKLOG + #define HTTP_SERVER_BACKLOG ( 12 ) +#endif + +#if !defined( ARRAY_SIZE ) + #define ARRAY_SIZE( x ) ( BaseType_t ) (sizeof( x ) / sizeof( x )[ 0 ] ) +#endif + +#if defined(__WIN32__) && !defined(ipconfigFTP_FS_USES_BACKSLAH) + #define ipconfigFTP_FS_USES_BACKSLAH 1 +#endif + +/* Some defines to make the code more readbale */ +#define pcCOMMAND_BUFFER pxClient->pxParent->pcCommandBuffer +#define pcNEW_DIR pxClient->pxParent->pcNewDir +#define pcFILE_BUFFER pxClient->pxParent->pcFileBuffer + +/* This FTP server will only do binary transfers */ +#define TMODE_BINARY 1 +#define TMODE_ASCII 2 +#define TMODE_7BITS 3 +#define TMODE_8BITS 4 + +/* Ascii character definitions. */ +#define ftpASCII_CR 13 +#define ftpASCII_LF 10 + +#if defined( FTP_WRITES_ALIGNED ) || defined( ipconfigFTP_WRITES_ALIGNED ) + #error Name change : please rename the define to the new name 'ipconfigFTP_ZERO_COPY_ALIGNED_WRITES' +#endif + +/* + * ipconfigFTP_ZERO_COPY_ALIGNED_WRITES : experimental optimisation option. + * If non-zero, receiving data will be done with the zero-copy method and also + * writes to disk will be done with sector-alignment as much as possible. + */ +#ifndef ipconfigFTP_ZERO_COPY_ALIGNED_WRITES + #define ipconfigFTP_ZERO_COPY_ALIGNED_WRITES 0 +#endif + +/* + * This module only has 2 public functions: + */ +BaseType_t xFTPClientWork( TCPClient_t *pxClient ); +void vFTPClientDelete( TCPClient_t *pxClient ); + +/* + * Process a single command. + */ +static BaseType_t prvProcessCommand( FTPClient_t *pxClient, BaseType_t xIndex, char *pcRestCommand ); + +/* + * Create a socket for a data connection to the FTP client. + */ +static BaseType_t prvTransferConnect( FTPClient_t *pxClient, BaseType_t xDoListen ); + +/* + * Either call listen() or connect() to start the transfer connection. + */ +static BaseType_t prvTransferStart( FTPClient_t *pxClient ); + +/* + * See if the socket has got connected or disconnected. Close the socket if + * necessary. + */ +static void prvTransferCheck( FTPClient_t *pxClient ); + +/* + * Close the data socket and issue some informative logging. + */ +static void prvTransferCloseSocket( FTPClient_t *pxClient ); + +/* + * Close the file handle (pxReadHandle or pxWriteHandle). + */ +static void prvTransferCloseFile( FTPClient_t *pxClient ); + +/* + * Close a directory (-handle). + */ +static void prvTransferCloseDir( FTPClient_t *pxClient ); + +/* + * Translate a string (indicating a transfer type) to a number. + */ +static BaseType_t prvGetTransferType( const char *pcType ); + +#if( ipconfigHAS_PRINTF != 0 ) + /* + * For nice logging: write an amount (number of bytes), e.g. 3512200 as + * "3.45 MB" + */ + static const char *pcMkSize( uint32_t ulAmount, char *pcBuffer, BaseType_t xBufferSize ); +#endif + +#if( ipconfigHAS_PRINTF != 0 ) + /* + * Calculate the average as bytes-per-second, when amount and milliseconds + * are known. + */ + static uint32_t ulGetAverage( uint32_t ulAmount, TickType_t xDeltaMs ); +#endif + +/* + * A port command looks like: PORT h1,h2,h3,h4,p1,p2. Parse it and translate it + * to an IP-address and a port number. + */ +static UBaseType_t prvParsePortData( const char *pcCommand, uint32_t *pulIPAddress ); + +/* + * CWD: Change current working directory. + */ + +static BaseType_t prvChangeDir( FTPClient_t *pxClient, char *pcDirectory ); + +/* + * RNFR: Rename from ... + */ +static BaseType_t prvRenameFrom( FTPClient_t *pxClient, const char *pcFileName ); + +/* + * RNTO: Rename to ... + */ +static BaseType_t prvRenameTo( FTPClient_t *pxClient, const char *pcFileName ); + +/* + * SITE: Change file permissions. + */ +static BaseType_t prvSiteCmd( FTPClient_t *pxClient, char *pcRestCommand ); + +/* + * DELE: Delete a file. + */ +static BaseType_t prvDeleteFile( FTPClient_t *pxClient, char *pcFileName ); + +/* + * SIZE: get the size of a file (xSendDate = 0). + * MDTM: get data and time properties (xSendDate = 1). + */ +static BaseType_t prvSizeDateFile( FTPClient_t *pxClient, char *pcFileName, BaseType_t xSendDate ); + +/* + * MKD: Make / create a directory (xDoRemove = 0). + * RMD: Remove a directory (xDoRemove = 1). + */ +static BaseType_t prvMakeRemoveDir( FTPClient_t *pxClient, const char *pcDirectory, BaseType_t xDoRemove ); + +/* + * The next three commands: LIST, RETR and STOR all require a data socket. + * The data connection is either started with a 'PORT' or a 'PASV' command. + * Each of the commands has a prepare- (Prep) and a working- (Work) function. + * The Work function should be called as long as the data socket is open, and + * there is data to be transmitted. + */ + +/* + * LIST: Send a directory listing in Unix style. + */ +static BaseType_t prvListSendPrep( FTPClient_t *pxClient ); +static BaseType_t prvListSendWork( FTPClient_t *pxClient ); + +/* + * RETR: Send a file to the FTP client. + */ +static BaseType_t prvRetrieveFilePrep( FTPClient_t *pxClient, char *pcFileName ); +static BaseType_t prvRetrieveFileWork( FTPClient_t *pxClient ); + +/* + * STOR: Receive a file from the FTP client and store it. + */ +static BaseType_t prvStoreFilePrep( FTPClient_t *pxClient, char *pcFileName ); +static BaseType_t prvStoreFileWork( FTPClient_t *pxClient ); + +/* + * Print/format a single directory entry in Unix style. + */ +static BaseType_t prvGetFileInfoStat( FF_DirEnt_t *pxEntry, char *pcLine, BaseType_t xMaxLength ); + +/* + * Send a reply to a socket, either the command- or the data-socket. + */ +static BaseType_t prvSendReply( Socket_t xSocket, const char *pcBuffer, BaseType_t xLength ); + +/* + * Prepend the root directory (if any), plus the current working directory + * (always), to get an absolute path. + */ +BaseType_t xMakeAbsolute( FTPClient_t *pxClient, char *pcBuffer, BaseType_t xBufferLength, const char *pcPath ); + +/* + +####### ##### ###### # # ## + # ## # # # # # # # # + # # # # # # # + # # # # # # # #### ### ## # # + ##### # ##### # # # # # # # # # # + # # # # # # # # # ## # #### + # # # ## ## # # # # # + # # # ## ## # # # # # +#### #### #### ## ## #### #### ## ## + + * xFTPClientWork() + * will be called by FreeRTOS_TCPServerWork(), after select has expired(). + * FD_ISSET will not be used. This work function will always be called at + * regular intervals, and also after a select() event has occurred. + */ +BaseType_t xFTPClientWork( TCPClient_t *pxTCPClient ) +{ +FTPClient_t *pxClient = ( FTPClient_t * ) pxTCPClient; +BaseType_t xRc; + + if( pxClient->bits.bHelloSent == pdFALSE_UNSIGNED ) + { + BaseType_t xLength; + + pxClient->bits.bHelloSent = pdTRUE_UNSIGNED; + + xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), + "220 Welcome to the FreeRTOS+TCP FTP server\r\n" ); + prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength ); + } + + /* Call recv() in a non-blocking way, to see if there is an FTP command + sent to this server. */ + xRc = FreeRTOS_recv( pxClient->xSocket, ( void * )pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), 0 ); + + if( xRc > 0 ) + { + BaseType_t xIndex; + const FTPCommand_t *pxCommand; + char *pcRestCommand; + + if( xRc < ( BaseType_t ) sizeof( pcCOMMAND_BUFFER ) ) + { + pcCOMMAND_BUFFER[ xRc ] = '\0'; + } + + while( xRc && ( ( pcCOMMAND_BUFFER[ xRc - 1 ] == ftpASCII_CR ) || ( pcCOMMAND_BUFFER[ xRc - 1 ] == ftpASCII_LF ) ) ) + { + pcCOMMAND_BUFFER[ --xRc ] = '\0'; + } + + /* Now iterate through a list of FTP commands, and look for a match. */ + pxCommand = xFTPCommands; + pcRestCommand = pcCOMMAND_BUFFER; + for( xIndex = 0; xIndex < FTP_CMD_COUNT - 1; xIndex++, pxCommand++ ) + { + BaseType_t xLength; + + /* The length of each command is stored as well, just to be a bit + quicker here. */ + xLength = pxCommand->xCommandLength; + + if( ( xRc >= xLength ) && ( memcmp( ( const void * ) pxCommand->pcCommandName, ( const void * ) pcCOMMAND_BUFFER, xLength ) == 0 ) ) + { + /* A match with an existing command is found. Skip any + whitespace to get the first parameter. */ + pcRestCommand += xLength; + while( ( *pcRestCommand == ' ' ) || ( *pcRestCommand == '\t' ) ) + { + pcRestCommand++; + } + break; + } + } + + /* If the command received was not recognised, xIndex will point to a + fake entry called 'ECMD_UNKNOWN'. */ + prvProcessCommand( pxClient, xIndex, pcRestCommand ); + } + else if( xRc < 0 ) + { + /* The connection will be closed and the client will be deleted. */ + FreeRTOS_printf( ( "xFTPClientWork: xRc = %ld\n", xRc ) ); + } + + /* Does it have an open data connection? */ + if( pxClient->xTransferSocket != FREERTOS_NO_SOCKET ) + { + /* See if the connection has changed. */ + prvTransferCheck( pxClient ); + + /* "pcConnectionAck" contains a string like: + "Response: 150 Accepted data connection from 192.168.2.3:6789" + The socket can only be used once this acknowledgement has been sent. */ + if( ( pxClient->xTransferSocket != FREERTOS_NO_SOCKET ) && ( pxClient->pcConnectionAck[ 0 ] == '\0' ) ) + { + BaseType_t xClientRc = 0; + + if( pxClient->bits1.bDirHasEntry ) + { + /* Still listing a directory. */ + xClientRc = prvListSendWork( pxClient ); + } + else if( pxClient->pxReadHandle != NULL ) + { + /* Sending a file. */ + xClientRc = prvRetrieveFileWork( pxClient ); + } + else if( pxClient->pxWriteHandle != NULL ) + { + /* Receiving a file. */ + xClientRc = prvStoreFileWork( pxClient ); + } + + if( xClientRc < 0 ) + { + prvTransferCloseSocket( pxClient ); + prvTransferCloseFile( pxClient ); + } + } + } + + return xRc; +} +/*-----------------------------------------------------------*/ + +static void prvTransferCloseDir( FTPClient_t *pxClient ) +{ + /* Nothing to close for +FAT. */ + ( void ) pxClient; +} +/*-----------------------------------------------------------*/ + +void vFTPClientDelete( TCPClient_t *pxTCPClient ) +{ +FTPClient_t *pxClient = ( FTPClient_t * ) pxTCPClient; + + /* Close any directory-listing-handles (not used by +FAT ). */ + prvTransferCloseDir( pxClient ); + /* Close the data-socket. */ + prvTransferCloseSocket( pxClient ); + /* Close any open file handle. */ + prvTransferCloseFile( pxClient ); + + /* Close the FTP command socket */ + if( pxClient->xSocket != FREERTOS_NO_SOCKET ) + { + FreeRTOS_FD_CLR( pxClient->xSocket, pxClient->pxParent->xSocketSet, eSELECT_ALL ); + FreeRTOS_closesocket( pxClient->xSocket ); + pxClient->xSocket = FREERTOS_NO_SOCKET; + } +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvProcessCommand( FTPClient_t *pxClient, BaseType_t xIndex, char *pcRestCommand ) +{ +const FTPCommand_t *pxFTPCommand = &( xFTPCommands[ xIndex ] ); +const char *pcMyReply = NULL; +BaseType_t xResult = 0; + + if( ( pxFTPCommand->ucCommandType != ECMD_PASS ) && ( pxFTPCommand->ucCommandType != ECMD_PORT ) ) + { + FreeRTOS_printf( ( " %s %s\n", pxFTPCommand->pcCommandName, pcRestCommand ) ); + } + + if( ( pxFTPCommand->checkLogin != pdFALSE ) && ( pxClient->bits.bLoggedIn == pdFALSE_UNSIGNED ) ) + { + pcMyReply = REPL_530; /* Please first log in. */ + } + else if( ( pxFTPCommand->checkNullArg != pdFALSE ) && ( ( pcRestCommand == NULL ) || ( pcRestCommand[ 0 ] == '\0' ) ) ) + { + pcMyReply = REPL_501; /* Command needs a parameter. */ + } + + if( pcMyReply == NULL ) + { + switch( pxFTPCommand->ucCommandType ) + { + case ECMD_USER: /* User. */ + /* User name has been entered, expect password. */ + pxClient->bits.bStatusUser = pdTRUE_UNSIGNED; + + #if( ipconfigFTP_HAS_USER_PASSWORD_HOOK != 0 )/*_RB_ Needs defaulting and adding to the web documentation. */ + { + /* Save the user name in 'pcFileName'. */ + snprintf( pxClient->pcFileName, sizeof( pxClient->pcFileName ), "%s", pcRestCommand ); + + /* The USER name is presented to the application. The function + may return a const string like "331 Please enter your + password\r\n". */ + pcMyReply = pcApplicationFTPUserHook( pxClient->pcFileName ); + if( pcMyReply == NULL ) + { + pcMyReply = REPL_331_ANON; + } + } + #else + { + /* No password checks, any password will be accepted. */ + pcMyReply = REPL_331_ANON; + } + #endif /* ipconfigFTP_HAS_USER_PASSWORD_HOOK != 0 */ + + #if( ipconfigFTP_HAS_USER_PROPERTIES_HOOK != 0 )/*_RB_ Needs defaulting and adding to the web documentation. */ + { + FTPUserProperties_t xProperties; + + xProperties.pcRootDir = pxClient->pcRootDir; + xProperties.xReadOnly = pdFALSE; + xProperties.usPortNumber = pxClient->usClientPort; + vApplicationFTPUserPropertiesHook( pxClient->pcFileName, &( xProperties ) ); + + if( xProperties.pcRootDir != NULL ) + { + pxClient->pcRootDir = xProperties.pcRootDir; + } + pxClient->bits.bReadOnly = ( xProperties.xReadOnly != pdFALSE_UNSIGNED ); + } + #endif /* ipconfigFTP_HAS_USER_PROPERTIES_HOOK */ + break; + + case ECMD_PASS: /* Password. */ + pxClient->ulRestartOffset = 0; + if( pxClient->bits.bStatusUser == pdFALSE_UNSIGNED ) + { + pcMyReply = REPL_503; /* "503 Bad sequence of commands.\r\n". */ + } + else + { + BaseType_t xAllow; + + pxClient->bits.bStatusUser = pdFALSE_UNSIGNED; + #if( ipconfigFTP_HAS_USER_PASSWORD_HOOK != 0 ) + { + xAllow = xApplicationFTPPasswordHook( pxClient->pcFileName, pcRestCommand ); + } + #else + { + xAllow = 1; + } + #endif /* ipconfigFTP_HAS_USER_PASSWORD_HOOK */ + + if( xAllow > 0 ) + { + pxClient->bits.bLoggedIn = pdTRUE_UNSIGNED; /* Client has now logged in. */ + pcMyReply = "230 OK. Current directory is /\r\n"; + } + else + { + pcMyReply = "530 Login incorrect\r\n"; /* 530 Login incorrect. */ + } + + strcpy( pxClient->pcCurrentDir, ( const char * ) "/" ); + } + break; + + case ECMD_SYST: /* System. */ + snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), "215 UNIX Type: L8\r\n" ); + pcMyReply = pcCOMMAND_BUFFER; + break; + + case ECMD_PWD: /* Get working directory. */ + xMakeRelative( pxClient, pcFILE_BUFFER, sizeof( pcFILE_BUFFER ), pxClient->pcCurrentDir ); + snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), REPL_257_PWD, pcFILE_BUFFER ); + pcMyReply = pcCOMMAND_BUFFER; + break; + + case ECMD_REST: + if( pxClient->bits.bReadOnly != pdFALSE_UNSIGNED ) + { + pcMyReply = REPL_553_READ_ONLY; + } + else + { + const char *pcPtr = pcRestCommand; + + while( *pcPtr == ' ' ) + { + pcPtr++; + } + + if( ( *pcPtr >= '0' ) && ( *pcPtr <= '9' ) ) + { + sscanf( pcPtr, "%lu", &pxClient->ulRestartOffset ); + snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), + "350 Restarting at %lu. Send STORE or RETRIEVE\r\n", pxClient->ulRestartOffset ); + pcMyReply = pcCOMMAND_BUFFER; + } + else + { + pcMyReply = REPL_500; /* 500 Syntax error, command unrecognised. */ + } + } + break; + + case ECMD_NOOP: /* NOP operation */ + if( pxClient->xTransferSocket != FREERTOS_NO_SOCKET ) + { + pcMyReply = REPL_200_PROGRESS; + } + else + { + pcMyReply = REPL_200; + } + break; + + case ECMD_TYPE: /* Ask or set transfer type. */ + { + /* e.g. "TYPE I" for Images (binary). */ + BaseType_t xType = prvGetTransferType( pcRestCommand ); + + if( xType < 0 ) + { + /* TYPE not recognised. */ + pcMyReply = REPL_500; + } + else + { + pxClient->xTransType = xType; + pcMyReply = REPL_200; + } + } + break; + + case ECMD_PASV: /* Enter passive mode. */ + /* Connect passive: Server will listen() and wait for a connection. + Start up a new data connection with 'xDoListen' set to true. */ + if( prvTransferConnect( pxClient, pdTRUE ) == pdFALSE ) + { + pcMyReply = REPL_502; + } + else + { + uint32_t ulIP; + uint16_t ulPort; + struct freertos_sockaddr xLocalAddress; + struct freertos_sockaddr xRemoteAddress; + + FreeRTOS_GetLocalAddress( pxClient->xTransferSocket, &xLocalAddress ); + FreeRTOS_GetRemoteAddress( pxClient->xSocket, &xRemoteAddress ); + + ulIP = FreeRTOS_ntohl( xLocalAddress.sin_addr ); + pxClient->ulClientIP = FreeRTOS_ntohl( xRemoteAddress.sin_addr ); + ulPort = FreeRTOS_ntohs( xLocalAddress.sin_port ); + + pxClient->usClientPort = FreeRTOS_ntohs( xRemoteAddress.sin_port ); + + /* REPL_227_D "227 Entering Passive Mode (%d,%d,%d,%d,%d,%d). */ + snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), REPL_227_D, + ( unsigned )ulIP >> 24, + ( unsigned )( ulIP >> 16 ) & 0xFF, + ( unsigned )( ulIP >> 8 ) & 0xFF, + ( unsigned )ulIP & 0xFF, + ( unsigned )ulPort >> 8, + ( unsigned )ulPort & 0xFF ); + + pcMyReply = pcCOMMAND_BUFFER; + } + break; + + case ECMD_PORT: /* Active connection to the client. */ + /* The client uses this command to tell the server to what + client-side port the server should contact; use of this command + indicates an active data transfer. e.g. PORT 192,168,1,2,4,19. */ + { + uint32_t ulIPAddress = 0; + UBaseType_t uxPort; + + uxPort = prvParsePortData( pcRestCommand, &ulIPAddress ); + FreeRTOS_printf( (" PORT %lxip:%ld\n", ulIPAddress, uxPort ) ); + + if( uxPort == 0u ) + { + pcMyReply = REPL_501; + } + else if( prvTransferConnect( pxClient, pdFALSE ) == pdFALSE ) + { + /* Call prvTransferConnect() with 'xDoListen' = false for an + active connect(). */ + pcMyReply = REPL_501; + } + else + { + pxClient->usClientPort = ( uint16_t ) uxPort; + pxClient->ulClientIP = ulIPAddress; + FreeRTOS_printf( ("Client address %lxip:%lu\n", ulIPAddress, uxPort ) ); + pcMyReply = REPL_200; + } + } + break; + + case ECMD_CWD: /* Change current working directory. */ + prvChangeDir( pxClient, pcRestCommand ); + break; + + case ECMD_RNFR: + if( pxClient->bits.bReadOnly != pdFALSE_UNSIGNED ) + { + pcMyReply = REPL_553_READ_ONLY; + } + else + { + prvRenameFrom( pxClient, pcRestCommand ); + } + break; + + case ECMD_RNTO: + if( pxClient->bits.bInRename == pdFALSE_UNSIGNED ) + { + pcMyReply = REPL_503; /* "503 Bad sequence of commands. */ + } + else + { + prvRenameTo( pxClient, pcRestCommand ); + } + break; + + case ECMD_SITE: /* Set file permissions */ + if( pxClient->bits.bReadOnly != pdFALSE_UNSIGNED ) + { + pcMyReply = REPL_553_READ_ONLY; + } + else if( prvSiteCmd( pxClient, pcRestCommand ) == pdFALSE ) + { + pcMyReply = REPL_202; + } + break; + + case ECMD_DELE: + if( pxClient->bits.bReadOnly != pdFALSE_UNSIGNED ) + { + pcMyReply = REPL_553_READ_ONLY; + } + else + { + prvDeleteFile( pxClient, pcRestCommand ); + } + break; + + case ECMD_MDTM: + prvSizeDateFile( pxClient, pcRestCommand, pdTRUE ); + break; + + case ECMD_SIZE: + if( pxClient->pxWriteHandle != NULL ) + { + /* This SIZE query is probably about a file which is now being + received. If so, return the value of pxClient->ulRecvBytes, + pcRestCommand points to 'pcCommandBuffer', make it free by + copying it to pcNewDir. */ + + xMakeAbsolute( pxClient, pcNEW_DIR, sizeof( pcNEW_DIR ), pcRestCommand ); + + if( strcmp( pcNEW_DIR, pcRestCommand ) == 0 ) + { + BaseType_t xCount; + for( xCount = 0; xCount < 3 && pxClient->pxWriteHandle; xCount++ ) + { + prvStoreFileWork( pxClient ); + } + if( pxClient->pxWriteHandle != NULL ) + { + /* File being queried is still open, return number of + bytes received until now. */ + snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), "213 %lu\r\n", pxClient->ulRecvBytes ); + pcMyReply = pcCOMMAND_BUFFER; + } /* otherwise, do a normal stat(). */ + } + strcpy( pcRestCommand, pcNEW_DIR ); + } + if( pcMyReply == NULL ) + { + prvSizeDateFile( pxClient, pcRestCommand, pdFALSE ); + } + break; + case ECMD_MKD: + case ECMD_RMD: + if( pxClient->bits.bReadOnly != pdFALSE_UNSIGNED ) + { + pcMyReply = REPL_553_READ_ONLY; + } + else + { + prvMakeRemoveDir( pxClient, pcRestCommand, pxFTPCommand->ucCommandType == ECMD_RMD ); + } + break; + case ECMD_CDUP: + prvChangeDir( pxClient, ".." ); + break; + + case ECMD_QUIT: + prvSendReply( pxClient->xSocket, REPL_221, 0 ); + pxClient->bits.bLoggedIn = pdFALSE_UNSIGNED; + break; + case ECMD_LIST: + case ECMD_RETR: + case ECMD_STOR: + if( ( pxClient->xTransferSocket == FREERTOS_NO_SOCKET ) && + ( ( pxFTPCommand->ucCommandType != ECMD_STOR ) || + ( pxClient->bits1.bEmptyFile == pdFALSE_UNSIGNED ) ) ) + { + /* Sending "425 Can't open data connection." : + Before receiving any of these commands, there must have been a + PORT or PASV command, which causes the creation of a data socket. */ + /* There is one exception: a STOR command is received while the + data connection has already been closed. This is tested with the + 'bEmptyFile' flag. */ + pcMyReply = REPL_425; + } + else + { + /* In case an empty file was received ( bits1.bEmptyFile ), the + transfer socket never delivered any data. Check if the transfer + socket is still open: */ + if( pxClient->xTransferSocket != FREERTOS_NO_SOCKET ) + { + prvTransferCheck( pxClient ); + } + switch( pxFTPCommand->ucCommandType ) + { + case ECMD_LIST: + prvListSendPrep( pxClient ); + break; + case ECMD_RETR: + prvRetrieveFilePrep( pxClient, pcRestCommand ); + break; + case ECMD_STOR: + if( pxClient->bits.bReadOnly != pdFALSE_UNSIGNED ) + { + pcMyReply = REPL_553_READ_ONLY; + } + else + { + prvStoreFilePrep( pxClient, pcRestCommand ); + if( pxClient->bits1.bEmptyFile != pdFALSE_UNSIGNED ) + { + /* Although the 'xTransferSocket' is closed already, + call this function just for the logging. */ + prvTransferCloseSocket( pxClient ); + + /* Close an empty file. */ + prvTransferCloseFile( pxClient ); + } + } + break; + } + } + break; + + case ECMD_FEAT: + { + static const char pcFeatAnswer[] = + "211-Features:\x0a" + /* The MDTM command is only allowed when + there is support for date&time. */ + #if( ffconfigTIME_SUPPORT != 0 ) + " MDTM\x0a" + #endif + " REST STREAM\x0a" + " SIZE\x0d\x0a" + "211 End\x0d\x0a"; + pcMyReply = pcFeatAnswer; + } + break; + + case ECMD_UNKNOWN: + FreeRTOS_printf( ("ftp::processCmd: Cmd %s unknown\n", pcRestCommand ) ); + pcMyReply = REPL_500; + break; + } + } + if( pxFTPCommand->ucCommandType != ECMD_RNFR ) + { + pxClient->bits.bInRename = pdFALSE_UNSIGNED; + } + + if( pcMyReply != NULL ) + { + xResult = prvSendReply( pxClient->xSocket, pcMyReply, strlen( pcMyReply ) ); + } + + return xResult; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvTransferConnect( FTPClient_t *pxClient, BaseType_t xDoListen ) +{ +Socket_t xSocket; +BaseType_t xResult; + + /* Open a socket for a data connection with the FTP client. + Happens after a PORT or a PASV command. */ + + /* Make sure the previous socket is deleted and flags reset */ + prvTransferCloseSocket( pxClient ); + + pxClient->bits1.bEmptyFile = pdFALSE_UNSIGNED; + + xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP ); + + if( ( xSocket != FREERTOS_NO_SOCKET ) && ( xSocket != FREERTOS_INVALID_SOCKET ) ) + { + BaseType_t xSmallTimeout = pdMS_TO_TICKS( 100 ); + struct freertos_sockaddr xAddress; + + #if( ipconfigFTP_TX_BUFSIZE > 0 ) + WinProperties_t xWinProps; + #endif + xAddress.sin_addr = FreeRTOS_GetIPAddress( ); /* Single NIC, currently not used */ + xAddress.sin_port = FreeRTOS_htons( 0 ); /* Bind to any available port number */ + + FreeRTOS_bind( xSocket, &xAddress, sizeof( xAddress ) ); + + #if( ipconfigFTP_TX_BUFSIZE > 0 ) + { + /* Fill in the buffer and window sizes that will be used by the + socket. */ + xWinProps.lTxBufSize = ipconfigFTP_TX_BUFSIZE; + xWinProps.lTxWinSize = ipconfigFTP_TX_WINSIZE; + xWinProps.lRxBufSize = ipconfigFTP_RX_BUFSIZE; + xWinProps.lRxWinSize = ipconfigFTP_RX_WINSIZE; + + /* Set the window and buffer sizes. */ + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_WIN_PROPERTIES, ( void * ) &xWinProps, sizeof( xWinProps ) ); + } + #endif + + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVTIMEO, ( void * ) &xSmallTimeout, sizeof( BaseType_t ) ); + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, ( void * ) &xSmallTimeout, sizeof( BaseType_t ) ); + + /* The same instance of the socket will be used for the connection and + data transport. */ + if( xDoListen != pdFALSE ) + { + BaseType_t xTrueValue = pdTRUE; + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_REUSE_LISTEN_SOCKET, ( void * ) &xTrueValue, sizeof( xTrueValue ) ); + } + pxClient->bits1.bIsListen = xDoListen; + pxClient->xTransferSocket = xSocket; + + if( xDoListen != pdFALSE ) + { + FreeRTOS_FD_SET( xSocket, pxClient->pxParent->xSocketSet, eSELECT_EXCEPT | eSELECT_READ ); + /* Calling FreeRTOS_listen( ) */ + xResult = prvTransferStart( pxClient ); + if( xResult >= 0 ) + { + xResult = pdTRUE; + } + } + else + { + FreeRTOS_FD_SET( xSocket, pxClient->pxParent->xSocketSet, eSELECT_EXCEPT | eSELECT_READ | eSELECT_WRITE ); + xResult = pdTRUE; + } + } + else + { + FreeRTOS_printf( ( "FreeRTOS_socket() failed\n" ) ); + xResult = -pdFREERTOS_ERRNO_ENOMEM; + } + + /* An active socket (PORT) should connect() later. */ + return xResult; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvTransferStart( FTPClient_t *pxClient ) +{ +BaseType_t xResult; + + /* A transfer socket has been opened, now either call listen() for 'PASV' + or connect() for the 'PORT' command. */ + if( pxClient->bits1.bIsListen != pdFALSE_UNSIGNED ) + { + xResult = FreeRTOS_listen( pxClient->xTransferSocket, 1 ); + } + else + { + struct freertos_sockaddr xAddress; + + xAddress.sin_addr = FreeRTOS_htonl( pxClient->ulClientIP ); + xAddress.sin_port = FreeRTOS_htons( pxClient->usClientPort ); + /* Start an active connection for this data socket */ + xResult = FreeRTOS_connect( pxClient->xTransferSocket, &xAddress, sizeof( xAddress ) ); + } + + return xResult; +} +/*-----------------------------------------------------------*/ + +static void prvTransferCheck( FTPClient_t *pxClient ) +{ +BaseType_t xRxSize; + + /* A data transfer is busy. Check if there are changes in connectedness. */ + xRxSize = FreeRTOS_rx_size( pxClient->xTransferSocket ); + + if( pxClient->bits1.bClientConnected == pdFALSE_UNSIGNED ) + { + /* The time to receive a small file can be so short, that we don't even + see that the socket gets connected and disconnected. Therefore, check + the sizeof of the RX buffer. */ + { + struct freertos_sockaddr xAddress; + Socket_t xNexSocket; + socklen_t xSocketLength = sizeof( xAddress ); + + if( pxClient->bits1.bIsListen != pdFALSE_UNSIGNED ) + { + xNexSocket = FreeRTOS_accept( pxClient->xTransferSocket, &xAddress, &xSocketLength); + if( ( ( xNexSocket != FREERTOS_NO_SOCKET ) && ( xNexSocket != FREERTOS_INVALID_SOCKET ) ) || + xRxSize > 0 ) + { + pxClient->bits1.bClientConnected = pdTRUE_UNSIGNED; + } + } + else + { + if( FreeRTOS_issocketconnected( pxClient->xTransferSocket ) > 0 || + xRxSize > 0 ) + { + pxClient->bits1.bClientConnected = pdTRUE_UNSIGNED; + } + } + if( pxClient->bits1.bClientConnected != pdFALSE_UNSIGNED ) + { + pxClient->bits1.bEmptyFile = pdFALSE_UNSIGNED; + #if( ipconfigHAS_PRINTF != 0 ) + { + struct freertos_sockaddr xRemoteAddress, xLocalAddress; + FreeRTOS_GetRemoteAddress( pxClient->xTransferSocket, &xRemoteAddress ); + FreeRTOS_GetLocalAddress( pxClient->xTransferSocket, &xLocalAddress ); + FreeRTOS_printf( ( "%s Connected from %u to %u\n", + pxClient->bits1.bIsListen != pdFALSE_UNSIGNED ? "PASV" : "PORT", + ( unsigned ) FreeRTOS_ntohs( xLocalAddress.sin_port ), + ( unsigned ) FreeRTOS_ntohs( xRemoteAddress.sin_port ) ) ); + } + #endif /* ipconfigHAS_PRINTF */ + FreeRTOS_FD_CLR( pxClient->xTransferSocket, pxClient->pxParent->xSocketSet, eSELECT_WRITE ); + FreeRTOS_FD_SET( pxClient->xTransferSocket, pxClient->pxParent->xSocketSet, eSELECT_READ|eSELECT_EXCEPT ); + } + } + } + + if ( pxClient->bits1.bClientConnected != pdFALSE_UNSIGNED ) + { + if( pxClient->pcConnectionAck[ 0 ] != '\0' ) + { + BaseType_t xLength; + BaseType_t xRemotePort; + struct freertos_sockaddr xRemoteAddress; + + FreeRTOS_GetRemoteAddress( pxClient->xTransferSocket, &xRemoteAddress ); + xRemotePort = FreeRTOS_ntohs( xRemoteAddress.sin_port ); + + /* Tell on the command port 21 we have a data connection */ + xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), + pxClient->pcConnectionAck, pxClient->ulClientIP, xRemotePort ); + + prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength ); + pxClient->pcConnectionAck[ 0 ] = '\0'; + } + + if( ( FreeRTOS_issocketconnected( pxClient->xTransferSocket ) == pdFALSE ) && FreeRTOS_rx_size( pxClient->xTransferSocket ) == 0 ) + { + prvTransferCloseSocket( pxClient ); + prvTransferCloseFile( pxClient ); + } + } +} +/*-----------------------------------------------------------*/ + +static void prvTransferCloseSocket( FTPClient_t *pxClient ) +{ + if( pxClient->xTransferSocket != FREERTOS_NO_SOCKET ) + { + /* DEBUGGING ONLY */ + BaseType_t xRxSize = FreeRTOS_rx_size( pxClient->xTransferSocket ); + if( xRxSize > 0 ) + { + BaseType_t xRxSize2; + BaseType_t xStatus; + prvStoreFileWork( pxClient ); + xStatus = FreeRTOS_connstatus( pxClient->xTransferSocket ); + xRxSize2 = FreeRTOS_rx_size( pxClient->xTransferSocket ); + FreeRTOS_printf( ( "FTP: WARNING: %s: RX size = %ld -> %ld (%s)\n", + FreeRTOS_GetTCPStateName( xStatus ), + xRxSize, xRxSize2, pxClient->pcFileName ) ); + if( xRxSize2 > 1 ) + { + return; + } + + /* Remove compiler warnings in case FreeRTOS_printf() is not + defined. */ + ( void ) xStatus; + } + } + + if( ( pxClient->pxWriteHandle != NULL ) || ( pxClient->pxReadHandle != NULL ) ) + { + BaseType_t xLength; + char pcStrBuf[ 32 ]; + + if( pxClient->bits1.bHadError == pdFALSE_UNSIGNED ) + { + xLength = snprintf( pxClient->pcClientAck, sizeof( pxClient->pcClientAck ), + "226 Closing connection %d bytes transmitted\r\n", ( int ) pxClient->ulRecvBytes ); + } + else + { + xLength = snprintf( pxClient->pcClientAck, sizeof( pxClient->pcClientAck ), + "451 Requested action aborted after %d bytes\r\n", ( int ) pxClient->ulRecvBytes ); + } + + /* Tell on the command socket the data connection is now closed. */ + prvSendReply( pxClient->xSocket, pxClient->pcClientAck, xLength ); + + #if( ipconfigHAS_PRINTF != 0 ) + { + TickType_t xDelta; + uint32_t ulAverage; + xDelta = xTaskGetTickCount( ) - pxClient->xStartTime; + ulAverage = ulGetAverage( pxClient->ulRecvBytes, xDelta ); + + FreeRTOS_printf( ("FTP: %s: '%s' %lu Bytes (%s/sec)\n", + pxClient->pxReadHandle ? "sent" : "recv", + pxClient->pcFileName, + pxClient->ulRecvBytes, + pcMkSize( ulAverage, pcStrBuf, sizeof( pcStrBuf ) ) ) ); + } + #endif + } + + if( pxClient->xTransferSocket != FREERTOS_NO_SOCKET ) + { + FreeRTOS_FD_CLR( pxClient->xTransferSocket, pxClient->pxParent->xSocketSet, eSELECT_ALL ); + FreeRTOS_closesocket( pxClient->xTransferSocket ); + pxClient->xTransferSocket = FREERTOS_NO_SOCKET; + if( pxClient->ulRecvBytes == 0ul ) + { + /* Received zero bytes: an empty file */ + pxClient->bits1.bEmptyFile = pdTRUE_UNSIGNED; + } + else + { + pxClient->bits1.bEmptyFile = pdFALSE_UNSIGNED; + } + } + pxClient->bits1.bIsListen = pdFALSE_UNSIGNED; + pxClient->bits1.bDirHasEntry = pdFALSE_UNSIGNED; + pxClient->bits1.bClientConnected = pdFALSE_UNSIGNED; + pxClient->bits1.bHadError = pdFALSE_UNSIGNED; +} +/*-----------------------------------------------------------*/ + +static void prvTransferCloseFile( FTPClient_t *pxClient ) +{ + if( pxClient->pxWriteHandle != NULL ) + { + ff_fclose( pxClient->pxWriteHandle ); + pxClient->pxWriteHandle = NULL; + #if( ipconfigFTP_HAS_RECEIVED_HOOK != 0 ) + { + vApplicationFTPReceivedHook( pxClient->pcFileName, pxClient->ulRecvBytes, pxClient ); + } + #endif + + } + if( pxClient->pxReadHandle != NULL ) + { + ff_fclose( pxClient->pxReadHandle ); + pxClient->pxReadHandle = NULL; + } + /* These two field are only used for logging / file-statistics */ + pxClient->ulRecvBytes = 0ul; + pxClient->xStartTime = 0ul; +} +/*-----------------------------------------------------------*/ + +/** + * Guess the transfer type, given the client requested type. + * Actually in unix there is no difference between binary and + * ascii mode when we work with file descriptors. + * If #type is not recognized as a valid client request, -1 is returned. + */ +static BaseType_t prvGetTransferType( const char *pcType ) +{ +BaseType_t xResult = -1; + + if( pcType != NULL ) + { + BaseType_t xLength = strlen( pcType ); + if( xLength == 0 ) + { + return -1; + } + switch( pcType[ 0 ] ) { + case 'I': + xResult = TMODE_BINARY; + break; + case 'A': + xResult = TMODE_ASCII; + break; + case 'L': + if( xLength >= 3 ) + { + if( pcType[ 2 ] == '7' ) + { + xResult = TMODE_7BITS; + } + else if( pcType[ 2 ] == '8' ) + { + xResult = TMODE_7BITS; + } + } + break; + } + } + return xResult; +} +/*-----------------------------------------------------------*/ + +#if( ipconfigHAS_PRINTF != 0 ) + #define SIZE_1_GB ( 1024ul * 1024ul * 1024ul ) + #define SIZE_1_MB ( 1024ul * 1024ul ) + #define SIZE_1_KB ( 1024ul ) + + static const char *pcMkSize( uint32_t ulAmount, char *pcBuffer, BaseType_t xBufferSize ) + { + uint32_t ulGB, ulMB, ulKB, ulByte; + + ulGB = ( ulAmount / SIZE_1_GB ); + ulAmount -= ( ulGB * SIZE_1_GB ); + ulMB = ( ulAmount / SIZE_1_MB ); + ulAmount -= ( ulMB * SIZE_1_MB ); + ulKB = ( ulAmount / SIZE_1_KB ); + ulAmount -= ( ulKB * SIZE_1_KB ); + ulByte = ( ulAmount ); + + if (ulGB != 0ul ) + { + snprintf( pcBuffer, xBufferSize, "%lu.%02lu GB", ulGB, (100 * ulMB) / SIZE_1_KB ); + } + else if( ulMB != 0ul ) + { + snprintf( pcBuffer, xBufferSize, "%lu.%02lu MB", ulMB, (100 * ulKB) / SIZE_1_KB ); + } + else if( ulKB != 0ul ) + { + snprintf(pcBuffer, xBufferSize, "%lu.%02lu KB", ulKB, (100 * ulByte) / SIZE_1_KB ); + } + else + { + snprintf( pcBuffer, xBufferSize, "%lu bytes", ulByte ); + } + + return pcBuffer; + } + /*-----------------------------------------------------------*/ +#endif /* ipconfigHAS_PRINTF != 0 */ + +#if( ipconfigHAS_PRINTF != 0 ) + static uint32_t ulGetAverage( uint32_t ulAmount, TickType_t xDeltaMs ) + { + uint32_t ulAverage; + + /* Get the average amount of bytes per seconds. Ideally this is + calculated by Multiplying with 1000 and dividing by milliseconds: + ulAverage = ( 1000ul * ulAmount ) / xDeltaMs; + Now get a maximum precision, while avoiding an arithmetic overflow: + */ + if( xDeltaMs == 0ul ) + { + /* Time is zero, there is no average */ + ulAverage = 0ul; + } + else if( ulAmount >= ( ~0ul / 10ul ) ) + { + /* More than 409 MB has been transferred, do not multiply. */ + ulAverage = ( ulAmount / ( xDeltaMs / 1000ul ) ); + } + else if( ulAmount >= ( ~0ul / 100ul ) ) + { + /* Between 409 and 41 MB has been transferred, can multiply by 10. */ + ulAverage = ( ( ulAmount * 10ul ) / ( xDeltaMs / 100ul ) ); + } + else if( ulAmount >= ( ~0ul / 1000ul ) ) + { + /* Between 4.1 MB and 41 has been transferred, can multiply by 100. */ + ulAverage = ( ( ulAmount * 100ul ) / ( xDeltaMs / 10ul ) ); + } + else + { + /* Less than 4.1 MB: can multiply by 1000. */ + ulAverage = ( ( ulAmount * 1000ul ) / xDeltaMs ); + } + + return ulAverage; + } + /*-----------------------------------------------------------*/ +#endif /* ipconfigHAS_PRINTF != 0 */ + +static UBaseType_t prvParsePortData( const char *pcCommand, uint32_t *pulIPAddress ) +{ +/*_HT_ Using 'unsigned' here because when sscanf() sees '%u', it expects a pointer to 'unsigned'. +Not sure about the sscanf() format for UBaseType_t ? */ +unsigned h1, h2, h3, h4, p1, p2; +char sep; +UBaseType_t uxResult; + + /* Expect PORT h1,h2,h3,h4,p1,p2 */ + if (sscanf (pcCommand, "%u%c%u%c%u%c%u%c%u%c%u", &h1, &sep, &h2, &sep, &h3, &sep, &h4, &sep, &p1, &sep, &p2) != 11) + { + uxResult= 0u; + } + else + { + /* Put in network byte order. */ + *pulIPAddress = + ( ( uint32_t ) h1 << 24 ) | + ( ( uint32_t ) h2 << 16 ) | + ( ( uint32_t ) h3 << 8 ) | + ( ( uint32_t ) h4 ); + uxResult = ( p1 << 8 ) | p2; + } + return uxResult; +} +/*-----------------------------------------------------------*/ + +/* + + #### ####### # ### +# # # # ## # # +# # # # # # +# ###### #### ### ## #### # # ### # #### + ## # # # # # # # # ##### # # # # + ## # # # ## # ###### # # # # ###### +# # # # # # # # # # # +# # # ## # # # # ## # # # # ## + #### ## #### #### #### #### ##### ##### #### + +*/ + +static BaseType_t prvStoreFilePrep( FTPClient_t *pxClient, char *pcFileName ) +{ +BaseType_t xResult; +FF_FILE *pxNewHandle; +size_t uxFileSize = 0ul; +int iErrorNo; + + /* Close previous handle (if any) and reset file transfer parameters. */ + prvTransferCloseFile( pxClient ); + + xMakeAbsolute( pxClient, pxClient->pcFileName, sizeof( pxClient->pcFileName ), pcFileName ); + + pxNewHandle = NULL; + + if( pxClient->ulRestartOffset != 0 ) + { + size_t uxOffset = pxClient->ulRestartOffset; + int32_t lRc; + + pxClient->ulRestartOffset = 0ul; /* Only use 1 time. */ + pxNewHandle = ff_fopen( pxClient->pcFileName, "ab" ); + + if( pxNewHandle != NULL ) + { + uxFileSize = pxNewHandle->ulFileSize; + + if( uxOffset <= uxFileSize ) + { + lRc = ff_fseek( pxNewHandle, uxOffset, FF_SEEK_SET ); + } + else + { + /* Won't even try to seek after EOF */ + lRc = -pdFREERTOS_ERRNO_EINVAL; + } + if( lRc != 0 ) + { + BaseType_t xLength; + + xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), + "450 Seek invalid %u length %u\r\n", + ( unsigned ) uxOffset, ( unsigned ) uxFileSize ); + + /* "Requested file action not taken". */ + prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength ); + + FreeRTOS_printf( ( "ftp::storeFile: create %s: Seek %u length %u\n", + pxClient->pcFileName, ( unsigned ) uxOffset, ( unsigned ) uxFileSize ) ); + + ff_fclose( pxNewHandle ); + pxNewHandle = NULL; + } + } + } + else + { + pxNewHandle = ff_fopen( pxClient->pcFileName, "wb" ); + } + + if( pxNewHandle == NULL ) + { + iErrorNo = stdioGET_ERRNO(); + if( iErrorNo == pdFREERTOS_ERRNO_ENOSPC ) + { + prvSendReply( pxClient->xSocket, REPL_552, 0 ); + } + else + { + /* "Requested file action not taken". */ + prvSendReply( pxClient->xSocket, REPL_450, 0 ); + } + FreeRTOS_printf( ( "ftp::storeFile: create %s: %s (errno %d)\n", + pxClient->pcFileName, + ( const char* ) strerror( iErrorNo ), iErrorNo ) ); + + xResult = pdFALSE; + } + else + { + if( pxClient->bits1.bIsListen ) + { + /* True if PASV is used. */ + snprintf( pxClient->pcConnectionAck, sizeof( pxClient->pcConnectionAck ), + "150 Accepted data connection from %%xip:%%u\r\n" ); + prvTransferCheck( pxClient ); + } + else + { + BaseType_t xLength; + + xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), "150 Opening BIN connection to store file\r\n" ); + prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength ); + pxClient->pcConnectionAck[ 0 ] = '\0'; + prvTransferStart( pxClient ); /* Now active connect. */ + } + + pxClient->pxWriteHandle = pxNewHandle; + + /* To get some statistics about the performance. */ + pxClient->xStartTime = xTaskGetTickCount( ); + + xResult = pdTRUE; + } + + return xResult; +} +/*-----------------------------------------------------------*/ + +#if( ipconfigFTP_ZERO_COPY_ALIGNED_WRITES == 0 ) + + static BaseType_t prvStoreFileWork( FTPClient_t *pxClient ) + { + BaseType_t xRc, xWritten; + + /* Read from the data socket until all has been read or until a negative value + is returned. */ + for( ; ; ) + { + char *pcBuffer; + + /* The "zero-copy" method: */ + xRc = FreeRTOS_recv( pxClient->xTransferSocket, ( void * ) &pcBuffer, + 0x20000u, FREERTOS_ZERO_COPY | FREERTOS_MSG_DONTWAIT ); + if( xRc <= 0 ) + { + break; + } + pxClient->ulRecvBytes += xRc; + xWritten = ff_fwrite( pcBuffer, 1, xRc, pxClient->pxWriteHandle ); + FreeRTOS_recv( pxClient->xTransferSocket, ( void * ) NULL, xRc, 0 ); + if( xWritten != xRc ) + { + xRc = -1; + /* bHadError: a transfer got aborted because of an error. */ + pxClient->bits1.bHadError = pdTRUE_UNSIGNED; + break; + } + } + return xRc; + } + +#else /* ipconfigFTP_ZERO_COPY_ALIGNED_WRITES != 0 */ + + #if !defined( ipconfigFTP_PREFERRED_WRITE_SIZE ) + /* If you store data on flash, it may be profitable to give 'ipconfigFTP_PREFERRED_WRITE_SIZE' + the same size as the size of the flash' erase blocks, e.g. 4KB */ + #define ipconfigFTP_PREFERRED_WRITE_SIZE 512ul + #endif + + static BaseType_t prvStoreFileWork( FTPClient_t *pxClient ) + { + BaseType_t xRc, xWritten; + + /* Read from the data socket until all has been read or until a negative + value is returned. */ + for( ; ; ) + { + char *pcBuffer; + UBaseType_t xStatus; + + /* The "zero-copy" method: */ + xRc = FreeRTOS_recv( pxClient->xTransferSocket, ( void * ) &pcBuffer, + 0x20000u, FREERTOS_ZERO_COPY | FREERTOS_MSG_DONTWAIT ); + + if( xRc <= 0 ) + { + /* There are no data or the connection is closed. */ + break; + } + xStatus = FreeRTOS_connstatus( pxClient->xTransferSocket ); + if( xStatus != eESTABLISHED ) + { + /* The connection is not established (any more), therefore + accept any amount of bytes, probably the last few bytes. */ + } + else + { + if( xRc >= ipconfigFTP_PREFERRED_WRITE_SIZE ) + { + /* More than a sector to write, round down to a multiple of + PREFERRED_WRITE_SIZE bytes. */ + xRc = ( xRc / ipconfigFTP_PREFERRED_WRITE_SIZE ) * ipconfigFTP_PREFERRED_WRITE_SIZE; + } + else + { + const StreamBuffer_t *pxBuffer = FreeRTOS_get_rx_buf( pxClient->xTransferSocket ); + size_t uxSpace = pxBuffer->LENGTH - pxBuffer->uxTail; + + if( uxSpace >= ipconfigFTP_PREFERRED_WRITE_SIZE ) + { + /* At this moment there are les than PREFERRED_WRITE_SIZE bytes in the RX + buffer, but there is space for more. Just return and + wait for more. */ + xRc = 0; + } + else + { + /* Now reading beyond the end of the circular buffer, + use a normal read. */ + pcBuffer = pcFILE_BUFFER; + xRc = FreeRTOS_recvcount( pxClient->xTransferSocket ); + xRc = ( xRc / ipconfigFTP_PREFERRED_WRITE_SIZE ) * ipconfigFTP_PREFERRED_WRITE_SIZE; + if( xRc > 0 ) + { + xRc = FreeRTOS_recv( pxClient->xTransferSocket, ( void * ) pcBuffer, + sizeof( pcFILE_BUFFER ), FREERTOS_MSG_DONTWAIT ); + } + } + } + } + if( xRc == 0 ) + { + break; + } + pxClient->ulRecvBytes += xRc; + + xWritten = ff_fwrite( pcBuffer, 1, xRc, pxClient->pxWriteHandle ); + if( pcBuffer != pcFILE_BUFFER ) + { + FreeRTOS_recv( pxClient->xTransferSocket, ( void * ) NULL, xRc, 0 ); + } + if( xWritten != xRc ) + { + xRc = -1; + /* bHadError: a transfer got aborted because of an error. */ + pxClient->bits1.bHadError = pdTRUE_UNSIGNED; + break; + } + } + return xRc; + } + +#endif /* ipconfigFTP_ZERO_COPY_ALIGNED_WRITES */ +/*-----------------------------------------------------------*/ + +/* +###### # ####### # ### + # # # # # ## # # + # # # # # # + # # #### ###### ### ## ### #### # # #### # # ### # #### + ###### # # # # # # # # # # # # # ##### # # # # + # ## ###### # ## # # ###### # # ###### # # # # ###### + # # # # # # # # # # # # # # + # # # ## # ## # # # ## # # # ## # # # # ## +### ## #### ## #### ##### #### ## #### #### ##### ##### #### +*/ +static BaseType_t prvRetrieveFilePrep( FTPClient_t *pxClient, char *pcFileName ) +{ +BaseType_t xResult = pdTRUE; +size_t uxFileSize; + + /* Close previous handle (if any) and reset file transfer parameters */ + prvTransferCloseFile( pxClient ); + + xMakeAbsolute( pxClient, pxClient->pcFileName, sizeof( pxClient->pcFileName ), pcFileName ); + + pxClient->pxReadHandle = ff_fopen( pxClient->pcFileName, "rb" ); + if( pxClient->pxReadHandle == NULL ) + { + int iErrno = stdioGET_ERRNO(); + /* "Requested file action not taken". */ + prvSendReply( pxClient->xSocket, REPL_450, 0 ); + FreeRTOS_printf( ("prvRetrieveFilePrep: open '%s': errno %d: %s\n", + pxClient->pcFileName, iErrno, ( const char * ) strerror( iErrno ) ) ); + uxFileSize = 0ul; + xResult = pdFALSE; + } + else + { + uxFileSize = pxClient->pxReadHandle->ulFileSize; + pxClient->uxBytesLeft = uxFileSize; + if( pxClient->ulRestartOffset != 0ul ) + { + size_t uxOffset = pxClient->ulRestartOffset; + int32_t iRc; + + /* Only use 1 time. */ + pxClient->ulRestartOffset = 0; + + if( uxOffset < uxFileSize ) + { + iRc = ff_fseek( pxClient->pxReadHandle, uxOffset, FF_SEEK_SET ); + } + else + { + iRc = -pdFREERTOS_ERRNO_EINVAL; + } + if( iRc != 0 ) + { + BaseType_t xLength; + + xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), + "450 Seek invalid %u length %u\r\n", ( unsigned ) uxOffset, ( unsigned ) uxFileSize ); + + /* "Requested file action not taken". */ + prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength ); + + FreeRTOS_printf( ( "prvRetrieveFilePrep: create %s: Seek %u length %u\n", + pxClient->pcFileName, ( unsigned ) uxOffset, ( unsigned ) uxFileSize ) ); + + ff_fclose( pxClient->pxReadHandle ); + pxClient->pxReadHandle = NULL; + xResult = pdFALSE; + } + else + { + pxClient->uxBytesLeft = uxFileSize - pxClient->ulRestartOffset; + } + } + } + if( xResult != pdFALSE ) + { + if( pxClient->bits1.bIsListen != pdFALSE_UNSIGNED ) + { + /* True if PASV is used. */ + snprintf( pxClient->pcConnectionAck, sizeof( pxClient->pcConnectionAck ), + "150%cAccepted data connection from %%xip:%%u\r\n%s", + pxClient->xTransType == TMODE_ASCII ? '-' : ' ', + pxClient->xTransType == TMODE_ASCII ? "150 NOTE: ASCII mode requested, but binary mode used\r\n" : "" ); + } else { + BaseType_t xLength; + + xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), "150%cOpening data connection to %lxip:%u\r\n%s", + pxClient->xTransType == TMODE_ASCII ? '-' : ' ', + pxClient->ulClientIP, + pxClient->usClientPort, + pxClient->xTransType == TMODE_ASCII ? "150 NOTE: ASCII mode requested, but binary mode used\r\n" : "" ); + prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength ); + pxClient->pcConnectionAck[ 0 ] = '\0'; + prvTransferStart( pxClient ); + } + + /* Prepare the ACK which will be sent when all data has been sent. */ + snprintf( pxClient->pcClientAck, sizeof( pxClient->pcClientAck ), "%s", REPL_226 ); + + /* To get some statistics about the performance. */ + pxClient->xStartTime = xTaskGetTickCount( ); + if( uxFileSize == 0ul ) + { + FreeRTOS_shutdown( pxClient->xTransferSocket, FREERTOS_SHUT_RDWR ); + } + } + + return xResult; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvRetrieveFileWork( FTPClient_t *pxClient ) +{ +size_t uxSpace; +size_t uxCount, uxItemsRead; +BaseType_t xRc = 0; +BaseType_t xSetEvent = pdFALSE; + + do + { + #if( ipconfigFTP_TX_ZERO_COPY != 0 ) + char *pcBuffer; + BaseType_t xBufferLength; + #endif /* ipconfigFTP_TX_ZERO_COPY */ + + /* Take the lesser of the two: tx_space (number of bytes that can be + queued for transmission) and uxBytesLeft (the number of bytes left to + read from the file) */ + uxSpace = FreeRTOS_tx_space( pxClient->xTransferSocket ); + + if( uxSpace == 0 ) + { + FreeRTOS_FD_SET( pxClient->xTransferSocket, pxClient->pxParent->xSocketSet, eSELECT_WRITE | eSELECT_EXCEPT ); + xRc = FreeRTOS_select( pxClient->pxParent->xSocketSet, 200 ); + uxSpace = FreeRTOS_tx_space( pxClient->xTransferSocket ); + } + + uxCount = FreeRTOS_min_uint32( pxClient->uxBytesLeft, uxSpace ); + + if( uxCount == 0 ) + { + break; + } + + #if( ipconfigFTP_TX_ZERO_COPY == 0 ) + { + if( uxCount > sizeof( pcFILE_BUFFER ) ) + { + uxCount = sizeof( pcFILE_BUFFER ); + } + uxItemsRead = ff_fread( pcFILE_BUFFER, 1, uxCount, pxClient->pxReadHandle ); + if( uxItemsRead != uxCount ) + { + FreeRTOS_printf( ( "prvRetrieveFileWork: Got %u Expected %u\n", ( unsigned )uxItemsRead, ( unsigned ) uxCount ) ); + xRc = FreeRTOS_shutdown( pxClient->xTransferSocket, FREERTOS_SHUT_RDWR ); + pxClient->uxBytesLeft = 0u; + break; + } + pxClient->uxBytesLeft -= uxCount; + + if( pxClient->uxBytesLeft == 0u ) + { + BaseType_t xTrueValue = 1; + + FreeRTOS_setsockopt( pxClient->xTransferSocket, 0, FREERTOS_SO_CLOSE_AFTER_SEND, ( void * ) &xTrueValue, sizeof( xTrueValue ) ); + } + + xRc = FreeRTOS_send( pxClient->xTransferSocket, pcFILE_BUFFER, uxCount, 0 ); + } + #else /* ipconfigFTP_TX_ZERO_COPY != 0 */ + { + /* Use zero-copy transmission: + FreeRTOS_get_tx_head() returns a direct pointer to the TX stream and + set xBufferLength to know how much space there is left. */ + pcBuffer = ( char * )FreeRTOS_get_tx_head( pxClient->xTransferSocket, &xBufferLength ); + if( ( pcBuffer != NULL ) && ( xBufferLength >= 512 ) ) + { + /* Will read disk data directly to the TX stream of the socket. */ + uxCount = FreeRTOS_min_uint32( uxCount, ( uint32_t )xBufferLength ); + if( uxCount > ( size_t ) 0x40000u ) + { + uxCount = ( size_t ) 0x40000u; + } + } + else + { + /* Use the normal file i/o buffer. */ + pcBuffer = pcFILE_BUFFER; + if( uxCount > sizeof( pcFILE_BUFFER ) ) + { + uxCount = sizeof( pcFILE_BUFFER ); + } + } + + if ( pxClient->uxBytesLeft >= 1024u ) + { + uxCount &= ~( ( size_t ) 512u - 1u ); + } + + if( uxCount <= 0u ) + { + /* Nothing to send after rounding down to a multiple of a sector size. */ + break; + } + + uxItemsRead = ff_fread( pcBuffer, 1, uxCount, pxClient->pxReadHandle ); + + if( uxCount != uxItemsRead ) + { + FreeRTOS_printf( ( "prvRetrieveFileWork: Got %u Expected %u\n", ( unsigned )uxItemsRead, ( unsigned )uxCount ) ); + xRc = FreeRTOS_shutdown( pxClient->xTransferSocket, FREERTOS_SHUT_RDWR ); + pxClient->uxBytesLeft = 0u; + break; + } + pxClient->uxBytesLeft -= uxCount; + + if( pxClient->uxBytesLeft == 0u ) + { + BaseType_t xTrueValue = 1; + + FreeRTOS_setsockopt( pxClient->xTransferSocket, 0, FREERTOS_SO_CLOSE_AFTER_SEND, ( void * ) &xTrueValue, sizeof( xTrueValue ) ); + } + if( pcBuffer != pcFILE_BUFFER ) + { + pcBuffer = NULL; + } + xRc = FreeRTOS_send( pxClient->xTransferSocket, pcBuffer, uxCount, 0 ); + } + #endif /* ipconfigFTP_TX_ZERO_COPY */ + + if( xRc < 0 ) + { + break; + } + + pxClient->ulRecvBytes += xRc; + if( pxClient->uxBytesLeft == 0u ) + { + break; + } + } while( uxCount > 0u ); + + if( xRc < 0 ) + { + FreeRTOS_printf( ( "prvRetrieveFileWork: already disconnected\n" ) ); + } + else if( pxClient->uxBytesLeft <= 0u ) + { + BaseType_t x; + + for( x = 0; x < 5; x++ ) + { + xRc = FreeRTOS_recv( pxClient->xTransferSocket, pcFILE_BUFFER, sizeof( pcFILE_BUFFER ), 0 ); + if( xRc < 0 ) + { + break; + } + } +// FreeRTOS_printf( ( "prvRetrieveFileWork: %s all sent: xRc %ld\n", pxClient->pcFileName, xRc ) ); + } + else + { + FreeRTOS_FD_SET( pxClient->xTransferSocket, pxClient->pxParent->xSocketSet, eSELECT_WRITE ); + xSetEvent = pdTRUE; + } + if( xSetEvent == pdFALSE ) + { + FreeRTOS_FD_CLR( pxClient->xTransferSocket, pxClient->pxParent->xSocketSet, eSELECT_WRITE ); + } + return xRc; +} +/*-----------------------------------------------------------*/ + +/* +### ##### #### ##### + # # # # # # # + # # # # # + # # # # + # # ## # + # # # ## # + # # # # # # + # # # # # # +####### ##### #### #### +*/ +/* Prepare sending a directory LIST */ +static BaseType_t prvListSendPrep( FTPClient_t *pxClient ) +{ +BaseType_t xFindResult; +int iErrorNo; + + if( pxClient->bits1.bIsListen != pdFALSE_UNSIGNED ) + { + /* True if PASV is used */ + snprintf( pxClient->pcConnectionAck, sizeof( pxClient->pcConnectionAck ), + "150 Accepted data connection from %%xip:%%u\r\n" ); + } + else + { + BaseType_t xLength; + + /* Here the FTP server is supposed to connect() */ + xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), + "150 Opening ASCII mode data connection to for /bin/ls \r\n" ); + + prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength ); + /* Clear the current connection acknowledge message */ + pxClient->pcConnectionAck[ 0 ] = '\0'; + prvTransferStart( pxClient ); + } + + pxClient->xDirCount = 0; + xMakeAbsolute( pxClient, pcNEW_DIR, sizeof( pcNEW_DIR ), pxClient->pcCurrentDir ); + + xFindResult = ff_findfirst( pcNEW_DIR, &pxClient->xFindData ); + + pxClient->bits1.bDirHasEntry = ( xFindResult >= 0 ); + + iErrorNo = stdioGET_ERRNO(); + if( ( xFindResult < 0 ) && ( iErrorNo == pdFREERTOS_ERRNO_ENMFILE ) ) + { + FreeRTOS_printf( ("prvListSendPrep: Empty directory? (%s)\n", pxClient->pcCurrentDir ) ); + prvSendReply( pxClient->xTransferSocket, "total 0\r\n", 0 ); + pxClient->xDirCount++; + } + else if( xFindResult < 0 ) + { + FreeRTOS_printf( ( "prvListSendPrep: rc = %ld iErrorNo = %d\n", xFindResult, iErrorNo ) ); + prvSendReply( pxClient->xSocket, REPL_451, 0 ); + } + pxClient->pcClientAck[ 0 ] = '\0'; + + return pxClient->xDirCount; +} +/*-----------------------------------------------------------*/ + +#define MAX_DIR_LIST_ENTRY_SIZE 256 + +static BaseType_t prvListSendWork( FTPClient_t *pxClient ) +{ +BaseType_t xTxSpace; + + while( pxClient->bits1.bClientConnected != pdFALSE_UNSIGNED ) + { + char *pcWritePtr = pcCOMMAND_BUFFER; + BaseType_t xWriteLength; + + xTxSpace = FreeRTOS_tx_space( pxClient->xTransferSocket ); + + if( xTxSpace > ( BaseType_t ) sizeof( pcCOMMAND_BUFFER ) ) + { + xTxSpace = sizeof( pcCOMMAND_BUFFER ); + } + + while( ( xTxSpace >= MAX_DIR_LIST_ENTRY_SIZE ) && ( pxClient->bits1.bDirHasEntry != pdFALSE_UNSIGNED ) ) + { + BaseType_t xLength, xEndOfDir; + int32_t iRc; + int iErrorNo; + + xLength = prvGetFileInfoStat( &( pxClient->xFindData.xDirectoryEntry ), pcWritePtr, xTxSpace ); + + pxClient->xDirCount++; + pcWritePtr += xLength; + xTxSpace -= xLength; + + iRc = ff_findnext( &pxClient->xFindData ); + iErrorNo = stdioGET_ERRNO(); + + xEndOfDir = ( iRc < 0 ) && ( iErrorNo == pdFREERTOS_ERRNO_ENMFILE ); + + pxClient->bits1.bDirHasEntry = ( xEndOfDir == pdFALSE ) && ( iRc >= 0 ); + + if( ( iRc < 0 ) && ( xEndOfDir == pdFALSE ) ) + { + FreeRTOS_printf( ("prvListSendWork: %s (rc %08x)\n", + ( const char * ) strerror( iErrorNo ), + ( unsigned )iRc ) ); + } + } + xWriteLength = ( BaseType_t ) ( pcWritePtr - pcCOMMAND_BUFFER ); + + if( xWriteLength == 0 ) + { + break; + } + + if( pxClient->bits1.bDirHasEntry == pdFALSE_UNSIGNED ) + { + uint32_t ulTotalCount; + uint32_t ulFreeCount; + uint32_t ulPercentage; + + ulTotalCount = 1; + ulFreeCount = ff_diskfree( pxClient->pcCurrentDir, &ulTotalCount ); + ulPercentage = ( uint32_t ) ( ( 100ULL * ulFreeCount + ulTotalCount / 2 ) / ulTotalCount ); + + /* Prepare the ACK which will be sent when all data has been sent. */ + snprintf( pxClient->pcClientAck, sizeof( pxClient->pcClientAck ), + "226-Options: -l\r\n" + "226-%ld matches total\r\n" + "226 Total %lu KB (%lu %% free)\r\n", + pxClient->xDirCount, ulTotalCount /1024, ulPercentage ); + } + + if( xWriteLength ) + { + if( pxClient->bits1.bDirHasEntry == pdFALSE_UNSIGNED ) + { + BaseType_t xTrueValue = 1; + + FreeRTOS_setsockopt( pxClient->xTransferSocket, 0, FREERTOS_SO_CLOSE_AFTER_SEND, ( void * ) &xTrueValue, sizeof( xTrueValue ) ); + } + + prvSendReply( pxClient->xTransferSocket, pcCOMMAND_BUFFER, xWriteLength ); + } + + if( pxClient->bits1.bDirHasEntry == pdFALSE_UNSIGNED ) + { + prvSendReply( pxClient->xSocket, pxClient->pcClientAck, 0 ); + break; + } + + } /* while( pxClient->bits1.bClientConnected ) */ + + return 0; +} +/*-----------------------------------------------------------*/ + +static const char *pcMonthAbbrev( BaseType_t xMonth ) +{ +static const char pcMonthList[] = "JanFebMarAprMayJunJulAugSepOctNovDec"; + + if( xMonth < 1 || xMonth > 12 ) + xMonth = 12; + + return pcMonthList + 3 * ( xMonth - 1 ); +}; +/*-----------------------------------------------------------*/ + +static BaseType_t prvGetFileInfoStat( FF_DirEnt_t *pxEntry, char *pcLine, BaseType_t xMaxLength ) +{ + char date[ 16 ]; + char mode[ 11 ] = "----------"; + BaseType_t st_nlink = 1; + const char user[ 9 ] = "freertos"; + const char group[ 8 ] = "plusfat"; + +/* + * Creates a unix-style listing, understood by most FTP clients: + * + * -rw-rw-r-- 1 freertos FreeRTOS+FAT 10564588 Sep 01 00:17 03. Metaharmoniks - Star (Instrumental).mp3 + * -rw-rw-r-- 1 freertos FreeRTOS+FAT 19087839 Sep 01 00:17 04. Simon Le Grec - Dimitri (Wherever U Are) (Cosmos Mix).mp3 + * -rw-rw-r-- 1 freertos FreeRTOS+FAT 11100621 Sep 01 00:16 05. D-Chill - Mistake (feat. Katy Blue).mp3 + */ + + #if ( ffconfigTIME_SUPPORT == 1 ) + const FF_SystemTime_t *pxCreateTime = &( pxEntry->xCreateTime ); + #else + #warning Do not use this. + FF_SystemTime_t xCreateTime; + const FF_SystemTime_t *pxCreateTime = &xCreateTime; + #endif + size_t ulSize = ( size_t )pxEntry->ulFileSize; + const char *pcFileName = pxEntry->pcFileName; + + mode[ 0 ] = ( ( pxEntry->ucAttrib & FF_FAT_ATTR_DIR ) != 0 ) ? 'd' : '-'; + #if( ffconfigDEV_SUPPORT != 0 ) + { + if( ( pxEntry->ucAttrib & FF_FAT_ATTR_DIR ) == 0 ) + { + switch( pxEntry->ucIsDeviceDir ) + { + case FF_DEV_CHAR_DEV: + mode[ 0 ] = 'c'; + break; + case FF_DEV_BLOCK_DEV: + mode[ 0 ] = 'b'; + break; + } + } + } + #endif /* ffconfigDEV_SUPPORT != 0 */ + + mode[ 1 ] = 'r'; /* Owner. */ + mode[ 2 ] = ( ( pxEntry->ucAttrib & FF_FAT_ATTR_READONLY ) != 0 ) ? '-' : 'w'; + mode[ 3 ] = '-'; /* x for executable. */ + + mode[ 4 ] = 'r'; /* group. */ + mode[ 5 ] = ( ( pxEntry->ucAttrib & FF_FAT_ATTR_READONLY ) != 0 ) ? '-' : 'w'; + mode[ 6 ] = '-'; /* x for executable. */ + + mode[ 7 ] = 'r'; /* world. */ + mode[ 8 ] = '-'; + mode[ 9 ] = '-'; /* x for executable. */ + + if( pxCreateTime->Month && pxCreateTime->Day ) + { + snprintf( date, sizeof( date ), "%-3.3s %02d %02d:%02d", + pcMonthAbbrev( pxCreateTime->Month ), + pxCreateTime->Day, + pxCreateTime->Hour, + pxCreateTime->Minute ); + } + else + { + snprintf (date, sizeof( date ), "Jan 01 1970"); + } + return snprintf( pcLine, xMaxLength, "%s %3ld %-4s %-4s %8d %12s %s\r\n", + mode, st_nlink, user, group, ( int ) ulSize, date, pcFileName ); +} +/*-----------------------------------------------------------*/ + +/* + #### # # ##### + # # # # # # +# # # # # # +# # # # # # +# # # # # # +# # # # # # +# # ## ## # # + # # ## ## # # + #### ## ## ##### +*/ +static BaseType_t prvChangeDir( FTPClient_t *pxClient, char *pcDirectory ) +{ +BaseType_t xResult; +BaseType_t xIsRootDir, xLength, xValid; +BaseType_t xIsDotDir = 0; + + if( pcDirectory[ 0 ] == '.' ) + { + if( ( pcDirectory[ 1 ] == '.' ) && + ( pcDirectory[ 2 ] == '\0' ) ) + { + xIsDotDir = 2; + } + else if( pcDirectory[ 1 ] == '\0' ) + { + xIsDotDir = 1; + } + } + + if( xIsDotDir != 0 ) + { + strcpy( pcFILE_BUFFER, pxClient->pcCurrentDir ); + + if( pcDirectory[ 1 ] == '.' ) + { + char *p = strrchr( pcFILE_BUFFER, '/' ); + if( p != NULL ) + { + if( p == pcFILE_BUFFER ) + { + p[ 1 ] = '\0'; + } + else + { + p[ 0 ] = '\0'; + } + } + } + } + else + { + if(pcDirectory[ 0 ] != '/' ) + { + BaseType_t xCurLength; + + xCurLength = strlen( pxClient->pcCurrentDir ); + snprintf( pcFILE_BUFFER, sizeof( pcFILE_BUFFER ), "%s%s%s", + pxClient->pcCurrentDir, + pxClient->pcCurrentDir[ xCurLength - 1 ] == '/' ? "" : "/", + pcDirectory ); + } + else + { + snprintf( pcFILE_BUFFER, sizeof( pcFILE_BUFFER ), "%s", pcDirectory ); + } + } + + xIsRootDir = ( pcFILE_BUFFER[ 0 ] == '/' ) && ( pcFILE_BUFFER[ 1 ] == '\0' ); + xMakeAbsolute( pxClient, pcNEW_DIR, sizeof( pcNEW_DIR ), pcFILE_BUFFER ); + + if( ( ( xIsRootDir == pdFALSE ) || ( FF_FS_Count() == 0 ) ) && ( ff_finddir( pcNEW_DIR ) == pdFALSE ) ) + { + xValid = pdFALSE; + } + else + { + xValid = pdTRUE; + } + + if( xValid == pdFALSE ) + { + /* Get the directory cluster, if it exists. */ + FreeRTOS_printf( ("FTP: chdir \"%s\": No such dir\n", pcNEW_DIR ) ); + //#define REPL_550 "550 Requested action not taken.\r\n" + //550 /home/hein/arch/h8300: No such file or directory + xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), + "550 %s: No such file or directory\r\n", + pcNEW_DIR ); + prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength ); + xResult = pdFALSE; + } + else + { + memcpy( pxClient->pcCurrentDir, pcNEW_DIR, sizeof( pxClient->pcCurrentDir ) ); + + xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), "250 Changed to %s\r\n", pcNEW_DIR ); + prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength ); + xResult = pdTRUE; + } + + return xResult; +} +/*-----------------------------------------------------------*/ + +/* +###### ## # ####### ###### + # # ## # # ## # # + # # ## # # # # # + # # ### # # # # # + ###### # ## # ##### ###### + # ## # ## # # # # ## + # # # ### # # # + # # # ## # # # +### ## # ## #### ### ## +*/ +static BaseType_t prvRenameFrom( FTPClient_t *pxClient, const char *pcFileName ) +{ +const char *myReply; +FF_FILE *fh; + + xMakeAbsolute( pxClient, pxClient->pcFileName, sizeof( pxClient->pcFileName ), pcFileName ); + + myReply = NULL; + + fh = ff_fopen( pxClient->pcFileName, "rb" ); + + if( fh != NULL ) + { + ff_fclose( fh ); + /* REPL_350; "350 Requested file action pending further information." */ + snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), + "350 Rename '%s' ...\r\n", pxClient->pcFileName ); + myReply = pcCOMMAND_BUFFER; + pxClient->bits.bInRename = pdTRUE_UNSIGNED; + } + else if( stdioGET_ERRNO() == pdFREERTOS_ERRNO_EISDIR ) + { + snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), + "350 Rename directory '%s' ...\r\n", pxClient->pcFileName ); + myReply = pcCOMMAND_BUFFER; + pxClient->bits.bInRename = pdTRUE_UNSIGNED; + } + else + { + FreeRTOS_printf( ("ftp::renameFrom[%s]\n%s\n", pxClient->pcFileName, strerror( stdioGET_ERRNO() ) ) ); + myReply = REPL_451; /* "451 Requested action aborted. Local error in processing." */ + } + if( myReply ) + { + prvSendReply( pxClient->xSocket, myReply, 0 ); + } + + return pdTRUE; +} +/*-----------------------------------------------------------*/ + +/* +###### ## # ##### ### + # # ## # # # # ## ## + # # ## # # ## ## + # # ### # # # # + ###### # ## # # # # + # ## # ## # # # # + # # # ### # ## ## + # # # ## # ## ## +### ## # ## #### ### +*/ +static BaseType_t prvRenameTo( FTPClient_t *pxClient, const char *pcFileName ) +{ +const char *myReply = NULL; +int iResult; + + xMakeAbsolute( pxClient, pcNEW_DIR, sizeof( pcNEW_DIR ), pcFileName ); + + /* FreeRTOS+FAT rename has an extra parameter: "remove target if already + exists". */ + iResult = ff_rename( pxClient->pcFileName, pcNEW_DIR, pdFALSE ); + + if( iResult < 0 ) + { + iResult = stdioGET_ERRNO(); + } + else + { + iResult = 0; + } + + switch( iResult ) + { + case 0: + FreeRTOS_printf( ( "ftp::renameTo[%s,%s]: Ok\n", pxClient->pcFileName, pcNEW_DIR ) ); + snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), + "250 Rename successful to '%s'\r\n", pcNEW_DIR ); + myReply = pcCOMMAND_BUFFER; + break; + case pdFREERTOS_ERRNO_EEXIST: + /* the destination file already exists. + "450 Requested file action not taken.\r\n"*/ + snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), + "450 Already exists '%s'\r\n", pcNEW_DIR ); + myReply = pcCOMMAND_BUFFER; + break; + case pdFREERTOS_ERRNO_EIO: /* FF_ERR_FILE_COULD_NOT_CREATE_DIRENT */ + /* if dirent creation failed (fatal error!). + "553 Requested action not taken.\r\n" */ + FreeRTOS_printf( ("ftp::renameTo[%s,%s]: Error creating DirEnt\n", + pxClient->pcFileName, pcNEW_DIR ) ); + myReply = REPL_553; + break; + case pdFREERTOS_ERRNO_ENXIO: + case pdFREERTOS_ERRNO_ENOENT: + /* if the source file was not found. + "450 Requested file action not taken.\r\n" */ + snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), + "450 No such file '%s'\r\n", pxClient->pcFileName ); + myReply = pcCOMMAND_BUFFER; + break; + default: + FreeRTOS_printf( ("ftp::renameTo[%s,%s]: %s\n", pxClient->pcFileName, pcNEW_DIR, + (const char*)strerror( stdioGET_ERRNO() ) ) ); + myReply = REPL_451; /* "451 Requested action aborted. Local error in processing." */ + break; + } + prvSendReply( pxClient->xSocket, myReply, 0 ); + + return pdTRUE; +} +/*-----------------------------------------------------------*/ + +/* + #### # +# # # # +# # # +# ### ###### #### + ## # # # # + ## # # ###### +# # # # # +# # # # ## # ## + #### ##### ## #### +*/ +static BaseType_t prvSiteCmd( FTPClient_t *pxClient, char *pcRestCommand ) +{ + ( void ) pxClient; + ( void ) pcRestCommand; + + return 0; +} +/*-----------------------------------------------------------*/ + +/* +##### ### + # # # # + # # # # + # # #### # #### ###### #### + # # # # # # # # # # + # # ###### # ###### # ###### + # # # # # # # + # # # ## # # ## # ## # ## +##### #### ##### #### ## #### +*/ +static BaseType_t prvDeleteFile( FTPClient_t *pxClient, char *pcFileName ) +{ +BaseType_t xResult, xLength; +int32_t iRc; +int iErrorNo; + + /* DELE: Delete a file. */ + xMakeAbsolute( pxClient, pxClient->pcFileName, sizeof( pxClient->pcFileName ), pcFileName ); + + iRc = ff_remove( pxClient->pcFileName ); + + if (iRc >= 0 ) + { + xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), + "250 File \"%s\" removed\r\n", pxClient->pcFileName ); + xResult = pdTRUE; + } + else + { + const char *errMsg = "other error"; + + iErrorNo = stdioGET_ERRNO(); + switch( iErrorNo ) + { /*_RB_ What do these negative numbers relate to? */ + case pdFREERTOS_ERRNO_ENOENT: errMsg = "No such file"; break; /* -31 File was not found. */ + case pdFREERTOS_ERRNO_EALREADY: errMsg = "File still open"; break; /* -30 File is in use. */ + case pdFREERTOS_ERRNO_EISDIR: errMsg = "Is a dir"; break; /* -32 Tried to FF_Open() a Directory. */ + case pdFREERTOS_ERRNO_EROFS: errMsg = "Read-only"; break; /* -33 Tried to FF_Open() a file marked read only. */ + case pdFREERTOS_ERRNO_ENOTDIR: errMsg = "Invalid path"; break; /* -34 The path of the file was not found. */ + } + FreeRTOS_printf( ( "ftp::delFile: '%s' because %s\n", + pxClient->pcFileName, strerror( iErrorNo ) ) ); + + xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), + "521-\"%s\" %s;\r\n" + "521 taking no action\r\n", + pxClient->pcFileName, errMsg ); + + xResult = pdFALSE; + } + + prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength ); + + return xResult; +} +/*-----------------------------------------------------------*/ + +/* + #### # ##### +# # # # # # +# # # # # +# ### ###### #### # # #### ###### #### + ## # # # # # # # # # # # + ## # # ###### # # ##### # ###### +# # # # # # # # # # # +# # # # # ## # # # # # ## # ## + #### ##### ###### #### ##### ### ## ## #### +*/ +static BaseType_t prvSizeDateFile( FTPClient_t *pxClient, char *pcFileName, BaseType_t xSendDate ) +{ +BaseType_t xResult = pdFALSE; +char *pcPtr; + + /* SIZE: get the size of a file (xSendDate = 0) + MDTM: get data and time properties (xSendDate = 1) */ + xMakeAbsolute( pxClient, pxClient->pcFileName, sizeof( pxClient->pcFileName ), pcFileName ); + + pcPtr = strrchr( pxClient->pcFileName, '/' ); + + if( ( pcPtr != NULL ) && ( pcPtr[ 1 ] != '\0' ) ) + { + FF_Stat_t xStatBuf; + int32_t iRc = ff_stat( pxClient->pcFileName, &xStatBuf ); + if (iRc < 0 ) + FreeRTOS_printf( ("In %s: %s\n", pxClient->pcFileName, + ( const char* )strerror( stdioGET_ERRNO() ) ) ); + + if( iRc == 0 ) + { + BaseType_t xLength; + /* "YYYYMMDDhhmmss" */ + if( xSendDate != pdFALSE ) + { + #if( ffconfigTIME_SUPPORT != 0 ) + { + FF_TimeStruct_t tmStruct; + time_t secs = xStatBuf.st_mtime; + FreeRTOS_gmtime_r( &secs, &tmStruct ); + + xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), "213 %04u%02u%02u%02u%02u%02u\r\n", + tmStruct.tm_year + 1900, + tmStruct.tm_mon+1, + tmStruct.tm_mday, + tmStruct.tm_hour, + tmStruct.tm_min, + tmStruct.tm_sec ); + } + #else + { + xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), "213 19700101000000\r\n", + } + #endif + } + else + { + xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), "213 %lu\r\n", xStatBuf.st_size ); + } + prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength ); + xResult = pdTRUE; + } + else + { + FreeRTOS_printf( ("ftp::sizeDateFile: No such file %s\n", pxClient->pcFileName ) ); + } + } else { + FreeRTOS_printf( ("ftp::sizeDateFile: Invalid file name: %s ?\n", pxClient->pcFileName ) ); + } + if( xResult == pdFALSE ) + { + prvSendReply( pxClient->xSocket, REPL_450, 0 ); /* "Requested file action not taken". */ + } + + return xResult; +} +/*-----------------------------------------------------------*/ + +/* +## ## ## ## ##### ###### ## ## ##### +### ### # # # # # # ### ### # # +# ### # # # # # # # # ### # # # +# # # # # # # # # # # # # # +# # # #### # # ###### # # # # # +# # # # # # # ## # # # # +# # # # # # # # # # # # +# # # # # # # # # # # # +# # ### ## ##### ### ## # # ##### +*/ +static BaseType_t prvMakeRemoveDir( FTPClient_t *pxClient, const char *pcDirectory, BaseType_t xDoRemove ) +{ +BaseType_t xResult; +BaseType_t xLength; +int32_t iRc; +int iErrorNo; + + /* MKD: Make / create a directory (xDoRemove = 0) + RMD: Remove a directory (xDoRemove = 1) */ + xMakeAbsolute( pxClient, pxClient->pcFileName, sizeof( pxClient->pcFileName ), pcDirectory ); + + if( xDoRemove ) + { + iRc = ff_rmdir( pxClient->pcFileName ); + } + else + { + #if( ffconfigMKDIR_RECURSIVE != 0 ) + { + iRc = ff_mkdir( pxClient->pcFileName, pdFALSE ); + } + #else + { + iRc = ff_mkdir( pxClient->pcFileName ); + } + #endif /* ffconfigMKDIR_RECURSIVE */ + } + xResult = pdTRUE; + + if( iRc >= 0 ) + { + xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), "257 \"%s\" directory %s\r\n", + pxClient->pcFileName, xDoRemove ? "removed" : "created" ); + } + else + { + const char *errMsg = "other error"; + BaseType_t xFTPCode = 521; + + xResult = pdFALSE; + iErrorNo = stdioGET_ERRNO(); + switch( iErrorNo ) + { + case pdFREERTOS_ERRNO_EEXIST: errMsg = "Directory already exists"; break; + case pdFREERTOS_ERRNO_ENOTDIR: errMsg = "Invalid path"; break; /* -34 The path of the file was not found. *//*_RB_ As before, what do these negative numbers relate to? */ + case pdFREERTOS_ERRNO_ENOTEMPTY:errMsg = "Dir not empty"; break; + case pdFREERTOS_ERRNO_EROFS: errMsg = "Read-only"; break; /* -33 Tried to FF_Open() a file marked read only. */ + default: errMsg = strerror( iErrorNo ); break; + } + if( iErrorNo == pdFREERTOS_ERRNO_ENOSPC ) + { + xFTPCode = 552; + } + xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), + "%ld-\"%s\" %s;\r\n" + "%ld taking no action\r\n", + xFTPCode, pxClient->pcFileName, errMsg, xFTPCode ); + FreeRTOS_printf( ( "%sdir '%s': %s\n", xDoRemove ? "rm" : "mk", pxClient->pcFileName, errMsg ) ); + } + prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength ); + + return xResult; +} +/*-----------------------------------------------------------*/ + +static portINLINE BaseType_t IsDigit( char cChar ) +{ +BaseType_t xResult; + + if( cChar >= '0' && cChar <= '9' ) + { + xResult = pdTRUE; + } + else + { + xResult = pdFALSE; + } + return xResult; +} + +static BaseType_t prvSendReply( Socket_t xSocket, const char *pcBuffer, BaseType_t xLength ) +{ +BaseType_t xResult; + + if( xLength == 0 ) + { + xLength = strlen( pcBuffer ); + } + xResult = FreeRTOS_send( xSocket, ( const void * )pcBuffer, ( size_t ) xLength, 0 ); + if( IsDigit( ( int ) pcBuffer[ 0 ] ) && + IsDigit( ( int ) pcBuffer[ 1 ] ) && + IsDigit( ( int ) pcBuffer[ 2 ] ) && + IsDigit( ( int ) pcBuffer[ 3 ] ) ) + { + const char *last = pcBuffer + strlen( pcBuffer ); + int iLength; + while( ( last > pcBuffer ) && ( ( last[ -1 ] == ftpASCII_CR ) || ( last[ -1 ] == ftpASCII_LF ) ) ) + { + last--; + } + iLength = ( int )( last - pcBuffer ); + FF_PRINTF( " %-*.*s", iLength, iLength, pcBuffer ); + } + return xResult; +} +/*-----------------------------------------------------------*/ + +#if( ipconfigFTP_HAS_RECEIVED_HOOK != 0 ) + + /* + * The following function is called for every file received: + * void vApplicationFTPReceivedHook( pcFileName, ulSize, pxFTPClient ); + * This callback function may do a callback to vFTPReplyMessage() to send messages + * to the FTP client like: + * 200-Please wait: Received new firmware + * 200-Please wait: Please wait a few seconds for reboot + */ + void vFTPReplyMessage( struct xFTP_CLIENT *pxFTPClient, const char *pcMessage ) + { + if( ( pxFTPClient != NULL ) && ( pxFTPClient->xSocket != NULL ) ) + { + prvSendReply( pxFTPClient->xSocket, pcMessage, 0 ); + } + } + /*-----------------------------------------------------------*/ + +#endif /* ipconfigFTP_HAS_RECEIVED_HOOK != 0 */ + +/* + * Some explanation: + * The FTP client may send: "DELE readme.txt" + * Here the complete path is constructed consisting of 3 parts: + * + * pxClient->pcRootDir + pxClient->pcCurrentDir + pcFileName + * + * 'pcCurrentDir' will not be applied for an absolute path like in "DELE /.htaccess" + */ +BaseType_t xMakeAbsolute( FTPClient_t *pxClient, char *pcBuffer, BaseType_t xBufferLength, const char *pcFileName ) +{ +BaseType_t xLength = strlen( pxClient->pcRootDir ); + + if( pcFileName[ 0 ] != '/' ) + { + char *pcNewDirBuffer = pcNEW_DIR; + BaseType_t xCurLength; + + xCurLength = strlen( pxClient->pcCurrentDir ); + if( pcBuffer == pcNEW_DIR ) + { + /* In one call, the result already goes into pcNEW_DIR. + Use pcFILE_BUFFER in that case */ + pcNewDirBuffer = pcFILE_BUFFER; + } + snprintf( pcNewDirBuffer, sizeof( pcNEW_DIR ), "%s%s%s", + pxClient->pcCurrentDir, + pxClient->pcCurrentDir[ xCurLength - 1 ] == '/' ? "" : "/", + pcFileName ); + pcFileName = pcNewDirBuffer; + } + if( strncasecmp( pxClient->pcRootDir, pcFileName, xLength ) == 0 ) + { + xLength = snprintf( pcBuffer, xBufferLength, "%s", pcFileName ); + } + else + { + xLength = snprintf( pcBuffer, xBufferLength, "%s/%s", + pxClient->pcRootDir, + pcFileName[ 0 ] == '/' ? ( pcFileName + 1 ) : pcFileName ); + } + + #if( ipconfigFTP_FS_USES_BACKSLAH == 1 ) + for( pcPtr = pcBuffer; *pcPtr; pcPtr++ ) + { + if( pcPtr[ 0 ] == '/' ) + { + pcPtr[ 0 ] = '\\'; + } + } + #endif + + return xLength; +} +/*-----------------------------------------------------------*/ + +BaseType_t xMakeRelative( FTPClient_t *pxClient, char *pcBuffer, BaseType_t xBufferLength, const char *pcFileName ) +{ +BaseType_t xLength = strlen( pxClient->pcRootDir ); + + if( strncasecmp ( pxClient->pcRootDir, pcFileName, xLength ) == 0 ) + { + xLength = snprintf( pcBuffer, xBufferLength, "%s", pcFileName + xLength ); + } + else + { + xLength = snprintf( pcBuffer, xBufferLength, "%s", pcFileName ); + } + + return xLength; +} +/*-----------------------------------------------------------*/ + +#endif /* ipconfigUSE_FTP */ + + + diff --git a/FreeRTOS-Plus/Demo/Common/Demo_IP_Protocols/HTTP/FreeRTOS_HTTP_commands.c b/FreeRTOS-Plus/Demo/Common/Demo_IP_Protocols/HTTP/FreeRTOS_HTTP_commands.c new file mode 100644 index 000000000..f8b5ac250 --- /dev/null +++ b/FreeRTOS-Plus/Demo/Common/Demo_IP_Protocols/HTTP/FreeRTOS_HTTP_commands.c @@ -0,0 +1,71 @@ +/* + * FreeRTOS+TCP V2.0.3 + * 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 + */ + + +/* Standard includes. */ +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" + +#include "FreeRTOS_HTTP_commands.h" + +const struct xWEB_COMMAND xWebCommands[ WEB_CMD_COUNT ] = +{ + { 3, "GET", ECMD_GET }, + { 4, "HEAD", ECMD_HEAD }, + { 4, "POST", ECMD_POST }, + { 3, "PUT", ECMD_PUT }, + { 6, "DELETE", ECMD_DELETE }, + { 5, "TRACE", ECMD_TRACE }, + { 7, "OPTIONS", ECMD_OPTIONS }, + { 7, "CONNECT", ECMD_CONNECT }, + { 5, "PATCH", ECMD_PATCH }, + { 4, "UNKN", ECMD_UNK }, +}; + +const char *webCodename (int aCode) +{ + switch (aCode) { + case WEB_REPLY_OK: // = 200, + return "OK"; + case WEB_NO_CONTENT: // 204 + return "No content"; + case WEB_BAD_REQUEST: // = 400, + return "Bad request"; + case WEB_UNAUTHORIZED: // = 401, + return "Authorization Required"; + case WEB_NOT_FOUND: // = 404, + return "Not Found"; + case WEB_GONE: // = 410, + return "Done"; + case WEB_PRECONDITION_FAILED: // = 412, + return "Precondition Failed"; + case WEB_INTERNAL_SERVER_ERROR: // = 500, + return "Internal Server Error"; + } + return "Unknown"; +} diff --git a/FreeRTOS-Plus/Demo/Common/Demo_IP_Protocols/HTTP/FreeRTOS_HTTP_server.c b/FreeRTOS-Plus/Demo/Common/Demo_IP_Protocols/HTTP/FreeRTOS_HTTP_server.c new file mode 100644 index 000000000..ee69fd11e --- /dev/null +++ b/FreeRTOS-Plus/Demo/Common/Demo_IP_Protocols/HTTP/FreeRTOS_HTTP_server.c @@ -0,0 +1,428 @@ +/* + * FreeRTOS+TCP V2.0.3 + * 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 + */ + +/* Standard includes. */ +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" + +/* FreeRTOS Protocol includes. */ +#include "FreeRTOS_HTTP_commands.h" +#include "FreeRTOS_TCP_server.h" +#include "FreeRTOS_server_private.h" + +/* Remove the whole file if HTTP is not supported. */ +#if( ipconfigUSE_HTTP == 1 ) + +/* FreeRTOS+FAT includes. */ +#include "ff_stdio.h" + +#ifndef HTTP_SERVER_BACKLOG + #define HTTP_SERVER_BACKLOG ( 12 ) +#endif + +#ifndef USE_HTML_CHUNKS + #define USE_HTML_CHUNKS ( 0 ) +#endif + +#if !defined( ARRAY_SIZE ) + #define ARRAY_SIZE(x) ( BaseType_t ) (sizeof( x ) / sizeof( x )[ 0 ] ) +#endif + +/* Some defines to make the code more readbale */ +#define pcCOMMAND_BUFFER pxClient->pxParent->pcCommandBuffer +#define pcNEW_DIR pxClient->pxParent->pcNewDir +#define pcFILE_BUFFER pxClient->pxParent->pcFileBuffer + +#ifndef ipconfigHTTP_REQUEST_CHARACTER + #define ipconfigHTTP_REQUEST_CHARACTER '?' +#endif + +/*_RB_ Need comment block, although fairly self evident. */ +static void prvFileClose( HTTPClient_t *pxClient ); +static BaseType_t prvProcessCmd( HTTPClient_t *pxClient, BaseType_t xIndex ); +static const char *pcGetContentsType( const char *apFname ); +static BaseType_t prvOpenURL( HTTPClient_t *pxClient ); +static BaseType_t prvSendFile( HTTPClient_t *pxClient ); +static BaseType_t prvSendReply( HTTPClient_t *pxClient, BaseType_t xCode ); + +static const char pcEmptyString[1] = { '\0' }; + +typedef struct xTYPE_COUPLE +{ + const char *pcExtension; + const char *pcType; +} TypeCouple_t; + +static TypeCouple_t pxTypeCouples[ ] = +{ + { "html", "text/html" }, + { "css", "text/css" }, + { "js", "text/javascript" }, + { "png", "image/png" }, + { "jpg", "image/jpeg" }, + { "gif", "image/gif" }, + { "txt", "text/plain" }, + { "mp3", "audio/mpeg3" }, + { "wav", "audio/wav" }, + { "flac", "audio/ogg" }, + { "pdf", "application/pdf" }, + { "ttf", "application/x-font-ttf" }, + { "ttc", "application/x-font-ttf" } +}; + +void vHTTPClientDelete( TCPClient_t *pxTCPClient ) +{ +HTTPClient_t *pxClient = ( HTTPClient_t * ) pxTCPClient; + + /* This HTTP client stops, close / release all resources. */ + if( pxClient->xSocket != FREERTOS_NO_SOCKET ) + { + FreeRTOS_FD_CLR( pxClient->xSocket, pxClient->pxParent->xSocketSet, eSELECT_ALL ); + FreeRTOS_closesocket( pxClient->xSocket ); + pxClient->xSocket = FREERTOS_NO_SOCKET; + } + prvFileClose( pxClient ); +} +/*-----------------------------------------------------------*/ + +static void prvFileClose( HTTPClient_t *pxClient ) +{ + if( pxClient->pxFileHandle != NULL ) + { + FreeRTOS_printf( ( "Closing file: %s\n", pxClient->pcCurrentFilename ) ); + ff_fclose( pxClient->pxFileHandle ); + pxClient->pxFileHandle = NULL; + } +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvSendReply( HTTPClient_t *pxClient, BaseType_t xCode ) +{ +struct xTCP_SERVER *pxParent = pxClient->pxParent; +BaseType_t xRc; + + /* A normal command reply on the main socket (port 21). */ + char *pcBuffer = pxParent->pcFileBuffer; + + xRc = snprintf( pcBuffer, sizeof( pxParent->pcFileBuffer ), + "HTTP/1.1 %d %s\r\n" +#if USE_HTML_CHUNKS + "Transfer-Encoding: chunked\r\n" +#endif + "Content-Type: %s\r\n" + "Connection: keep-alive\r\n" + "%s\r\n", + ( int ) xCode, + webCodename (xCode), + pxParent->pcContentsType[0] ? pxParent->pcContentsType : "text/html", + pxParent->pcExtraContents ); + + pxParent->pcContentsType[0] = '\0'; + pxParent->pcExtraContents[0] = '\0'; + + xRc = FreeRTOS_send( pxClient->xSocket, ( const void * ) pcBuffer, xRc, 0 ); + pxClient->bits.bReplySent = pdTRUE_UNSIGNED; + + return xRc; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvSendFile( HTTPClient_t *pxClient ) +{ +size_t uxSpace; +size_t uxCount; +BaseType_t xRc = 0; + + if( pxClient->bits.bReplySent == pdFALSE_UNSIGNED ) + { + pxClient->bits.bReplySent = pdTRUE_UNSIGNED; + + strcpy( pxClient->pxParent->pcContentsType, pcGetContentsType( pxClient->pcCurrentFilename ) ); + snprintf( pxClient->pxParent->pcExtraContents, sizeof( pxClient->pxParent->pcExtraContents ), + "Content-Length: %d\r\n", ( int ) pxClient->uxBytesLeft ); + + /* "Requested file action OK". */ + xRc = prvSendReply( pxClient, WEB_REPLY_OK ); + } + + if( xRc >= 0 ) do + { + uxSpace = FreeRTOS_tx_space( pxClient->xSocket ); + + if( pxClient->uxBytesLeft < uxSpace ) + { + uxCount = pxClient->uxBytesLeft; + } + else + { + uxCount = uxSpace; + } + + if( uxCount > 0u ) + { + if( uxCount > sizeof( pxClient->pxParent->pcFileBuffer ) ) + { + uxCount = sizeof( pxClient->pxParent->pcFileBuffer ); + } + ff_fread( pxClient->pxParent->pcFileBuffer, 1, uxCount, pxClient->pxFileHandle ); + pxClient->uxBytesLeft -= uxCount; + + xRc = FreeRTOS_send( pxClient->xSocket, pxClient->pxParent->pcFileBuffer, uxCount, 0 ); + if( xRc < 0 ) + { + break; + } + } + } while( uxCount > 0u ); + + if( pxClient->uxBytesLeft == 0u ) + { + /* Writing is ready, no need for further 'eSELECT_WRITE' events. */ + FreeRTOS_FD_CLR( pxClient->xSocket, pxClient->pxParent->xSocketSet, eSELECT_WRITE ); + prvFileClose( pxClient ); + } + else + { + /* Wake up the TCP task as soon as this socket may be written to. */ + FreeRTOS_FD_SET( pxClient->xSocket, pxClient->pxParent->xSocketSet, eSELECT_WRITE ); + } + + return xRc; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvOpenURL( HTTPClient_t *pxClient ) +{ +BaseType_t xRc; +char pcSlash[ 2 ]; + + pxClient->bits.ulFlags = 0; + + #if( ipconfigHTTP_HAS_HANDLE_REQUEST_HOOK != 0 ) + { + if( strchr( pxClient->pcUrlData, ipconfigHTTP_REQUEST_CHARACTER ) != NULL ) + { + size_t xResult; + + xResult = uxApplicationHTTPHandleRequestHook( pxClient->pcUrlData, pxClient->pcCurrentFilename, sizeof( pxClient->pcCurrentFilename ) ); + if( xResult > 0 ) + { + strcpy( pxClient->pxParent->pcContentsType, "text/html" ); + snprintf( pxClient->pxParent->pcExtraContents, sizeof( pxClient->pxParent->pcExtraContents ), + "Content-Length: %d\r\n", ( int ) xResult ); + xRc = prvSendReply( pxClient, WEB_REPLY_OK ); /* "Requested file action OK" */ + if( xRc > 0 ) + { + xRc = FreeRTOS_send( pxClient->xSocket, pxClient->pcCurrentFilename, xResult, 0 ); + } + /* Although against the coding standard of FreeRTOS, a return is + done here to simplify this conditional code. */ + return xRc; + } + } + } + #endif /* ipconfigHTTP_HAS_HANDLE_REQUEST_HOOK */ + + if( pxClient->pcUrlData[ 0 ] != '/' ) + { + /* Insert a slash before the file name. */ + pcSlash[ 0 ] = '/'; + pcSlash[ 1 ] = '\0'; + } + else + { + /* The browser provided a starting '/' already. */ + pcSlash[ 0 ] = '\0'; + } + snprintf( pxClient->pcCurrentFilename, sizeof( pxClient->pcCurrentFilename ), "%s%s%s", + pxClient->pcRootDir, + pcSlash, + pxClient->pcUrlData); + + pxClient->pxFileHandle = ff_fopen( pxClient->pcCurrentFilename, "rb" ); + + FreeRTOS_printf( ( "Open file '%s': %s\n", pxClient->pcCurrentFilename, + pxClient->pxFileHandle != NULL ? "Ok" : strerror( stdioGET_ERRNO() ) ) ); + + if( pxClient->pxFileHandle == NULL ) + { + /* "404 File not found". */ + xRc = prvSendReply( pxClient, WEB_NOT_FOUND ); + } + else + { + pxClient->uxBytesLeft = ( size_t ) pxClient->pxFileHandle->ulFileSize; + xRc = prvSendFile( pxClient ); + } + + return xRc; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvProcessCmd( HTTPClient_t *pxClient, BaseType_t xIndex ) +{ +BaseType_t xResult = 0; + + /* A new command has been received. Process it. */ + switch( xIndex ) + { + case ECMD_GET: + xResult = prvOpenURL( pxClient ); + break; + + case ECMD_HEAD: + case ECMD_POST: + case ECMD_PUT: + case ECMD_DELETE: + case ECMD_TRACE: + case ECMD_OPTIONS: + case ECMD_CONNECT: + case ECMD_PATCH: + case ECMD_UNK: + { + FreeRTOS_printf( ( "prvProcessCmd: Not implemented: %s\n", + xWebCommands[xIndex].pcCommandName ) ); + } + break; + } + + return xResult; +} +/*-----------------------------------------------------------*/ + +BaseType_t xHTTPClientWork( TCPClient_t *pxTCPClient ) +{ +BaseType_t xRc; +HTTPClient_t *pxClient = ( HTTPClient_t * ) pxTCPClient; + + if( pxClient->pxFileHandle != NULL ) + { + prvSendFile( pxClient ); + } + + xRc = FreeRTOS_recv( pxClient->xSocket, ( void * )pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), 0 ); + + if( xRc > 0 ) + { + BaseType_t xIndex; + const char *pcEndOfCmd; + const struct xWEB_COMMAND *curCmd; + char *pcBuffer = pcCOMMAND_BUFFER; + + if( xRc < ( BaseType_t ) sizeof( pcCOMMAND_BUFFER ) ) + { + pcBuffer[ xRc ] = '\0'; + } + while( xRc && ( pcBuffer[ xRc - 1 ] == 13 || pcBuffer[ xRc - 1 ] == 10 ) ) + { + pcBuffer[ --xRc ] = '\0'; + } + pcEndOfCmd = pcBuffer + xRc; + + curCmd = xWebCommands; + + /* Pointing to "/index.html HTTP/1.1". */ + pxClient->pcUrlData = pcBuffer; + + /* Pointing to "HTTP/1.1". */ + pxClient->pcRestData = pcEmptyString; + + /* Last entry is "ECMD_UNK". */ + for( xIndex = 0; xIndex < WEB_CMD_COUNT - 1; xIndex++, curCmd++ ) + { + BaseType_t xLength; + + xLength = curCmd->xCommandLength; + if( ( xRc >= xLength ) && ( memcmp( curCmd->pcCommandName, pcBuffer, xLength ) == 0 ) ) + { + char *pcLastPtr; + + pxClient->pcUrlData += xLength + 1; + for( pcLastPtr = (char *)pxClient->pcUrlData; pcLastPtr < pcEndOfCmd; pcLastPtr++ ) + { + char ch = *pcLastPtr; + if( ( ch == '\0' ) || ( strchr( "\n\r \t", ch ) != NULL ) ) + { + *pcLastPtr = '\0'; + pxClient->pcRestData = pcLastPtr + 1; + break; + } + } + break; + } + } + + if( xIndex < ( WEB_CMD_COUNT - 1 ) ) + { + xRc = prvProcessCmd( pxClient, xIndex ); + } + } + else if( xRc < 0 ) + { + /* The connection will be closed and the client will be deleted. */ + FreeRTOS_printf( ( "xHTTPClientWork: rc = %ld\n", xRc ) ); + } + return xRc; +} +/*-----------------------------------------------------------*/ + +static const char *pcGetContentsType (const char *apFname) +{ + const char *slash = NULL; + const char *dot = NULL; + const char *ptr; + const char *pcResult = "text/html"; + BaseType_t x; + + for( ptr = apFname; *ptr; ptr++ ) + { + if (*ptr == '.') dot = ptr; + if (*ptr == '/') slash = ptr; + } + if( dot > slash ) + { + dot++; + for( x = 0; x < ARRAY_SIZE( pxTypeCouples ); x++ ) + { + if( strcasecmp( dot, pxTypeCouples[ x ].pcExtension ) == 0 ) + { + pcResult = pxTypeCouples[ x ].pcType; + break; + } + } + } + return pcResult; +} + +#endif /* ipconfigUSE_HTTP */ + diff --git a/FreeRTOS-Plus/Demo/Common/Demo_IP_Protocols/NTP/NTPDemo.c b/FreeRTOS-Plus/Demo/Common/Demo_IP_Protocols/NTP/NTPDemo.c new file mode 100644 index 000000000..7795c41da --- /dev/null +++ b/FreeRTOS-Plus/Demo/Common/Demo_IP_Protocols/NTP/NTPDemo.c @@ -0,0 +1,440 @@ +/* + * FreeRTOS+TCP V2.0.3 + * 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 + */ + +/* + * NTPDemo.c + * + * An example of how to lookup a domain using DNS + * And also how to send and receive UDP messages to get the NTP time + * + */ + +/* Standard includes. */ +#include +#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" +#include "FreeRTOS_DNS.h" +#include "FreeRTOS_Stream_Buffer.h" + +/* Use the date & time functions from +FAT. */ +#include "ff_time.h" + +#include "NTPDemo.h" +#include "ntpClient.h" + +#include "date_and_time.h" + +enum EStatus { + EStatusLookup, + EStatusAsking, + EStatusPause, + EStatusFailed, +}; + +static struct SNtpPacket xNTPPacket; + +#if( ipconfigUSE_CALLBACKS == 0 ) + static char cRecvBuffer[ sizeof( struct SNtpPacket ) + 64 ]; +#endif + +static enum EStatus xStatus = EStatusLookup; + +static const char *pcTimeServers[] = { + "0.asia.pool.ntp.org", + "0.europe.pool.ntp.org", + "0.id.pool.ntp.org", + "0.south-america.pool.ntp.org", + "0.oceania.pool.ntp.org", + "0.north-america.pool.ntp.org" +}; + +static SemaphoreHandle_t xNTPWakeupSem = NULL; +static uint32_t ulIPAddressFound; +static Socket_t xUDPSocket = NULL; +static TaskHandle_t xNTPTaskhandle = NULL; +static TickType_t uxSendTime; + +static void prvNTPTask( void *pvParameters ); + +static void vSignalTask( void ) +{ + #if( ipconfigUSE_CALLBACKS == 0 ) + if( xUDPSocket != NULL ) + { + /* Send a signal to the socket so that the + FreeRTOS_recvfrom will get interrupted. */ + FreeRTOS_SignalSocket( xUDPSocket ); + } + else + #endif + if( xNTPWakeupSem != NULL ) + { + xSemaphoreGive( xNTPWakeupSem ); + } +} + +void vStartNTPTask( uint16_t usTaskStackSize, UBaseType_t uxTaskPriority ) +{ + /* The only public function in this module: start a task to contact + some NTP server. */ + + if( xNTPTaskhandle != NULL ) + { + switch( xStatus ) + { + case EStatusPause: + xStatus = EStatusAsking; + vSignalTask(); + break; + case EStatusLookup: + FreeRTOS_printf( ( "NTP looking up server\n" ) ); + break; + case EStatusAsking: + FreeRTOS_printf( ( "NTP still asking\n" ) ); + break; + case EStatusFailed: + FreeRTOS_printf( ( "NTP failed somehow\n" ) ); + ulIPAddressFound = 0ul; + xStatus = EStatusLookup; + vSignalTask(); + break; + } + } + else + { + xUDPSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP ); + if( xUDPSocket != NULL ) + { + struct freertos_sockaddr xAddress; + #if( ipconfigUSE_CALLBACKS != 0 ) + BaseType_t xReceiveTimeOut = pdMS_TO_TICKS( 0 ); + #else + BaseType_t xReceiveTimeOut = pdMS_TO_TICKS( 5000 ); + #endif + + xAddress.sin_addr = 0ul; + xAddress.sin_port = FreeRTOS_htons( NTP_PORT ); + + FreeRTOS_bind( xUDPSocket, &xAddress, sizeof( xAddress ) ); + FreeRTOS_setsockopt( xUDPSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) ); + xTaskCreate( prvNTPTask, /* The function that implements the task. */ + ( const char * ) "NTP client", /* Just a text name for the task to aid debugging. */ + usTaskStackSize, /* The stack size is defined in FreeRTOSIPConfig.h. */ + NULL, /* The task parameter, not used in this case. */ + uxTaskPriority, /* The priority assigned to the task is defined in FreeRTOSConfig.h. */ + &xNTPTaskhandle ); /* The task handle. */ + } + else + { + FreeRTOS_printf( ( "Creating socket failed\n" ) ); + } + } +} +/*-----------------------------------------------------------*/ + +static void vDNS_callback( const char *pcName, void *pvSearchID, uint32_t ulIPAddress ) +{ +char pcBuf[16]; + + /* The DNS lookup has a result, or it has reached the time-out. */ + FreeRTOS_inet_ntoa( ulIPAddress, pcBuf ); + FreeRTOS_printf( ( "IP address of %s found: %s\n", pcName, pcBuf ) ); + if( ulIPAddressFound == 0ul ) + { + ulIPAddressFound = ulIPAddress; + } + /* For testing: in case DNS doen't respond, still try some NTP server + with a known IP-address. */ + if( ulIPAddressFound == 0ul ) + { + ulIPAddressFound = FreeRTOS_inet_addr_quick( 184, 105, 182, 7 ); +/* ulIPAddressFound = FreeRTOS_inet_addr_quick( 103, 242, 70, 4 ); */ + } + xStatus = EStatusAsking; + + vSignalTask(); +} +/*-----------------------------------------------------------*/ + +static void prvSwapFields( struct SNtpPacket *pxPacket) +{ + /* NTP messages are big-endian */ + pxPacket->rootDelay = FreeRTOS_htonl( pxPacket->rootDelay ); + pxPacket->rootDispersion = FreeRTOS_htonl( pxPacket->rootDispersion ); + + pxPacket->referenceTimestamp.seconds = FreeRTOS_htonl( pxPacket->referenceTimestamp.seconds ); + pxPacket->referenceTimestamp.fraction = FreeRTOS_htonl( pxPacket->referenceTimestamp.fraction ); + + pxPacket->originateTimestamp.seconds = FreeRTOS_htonl( pxPacket->originateTimestamp.seconds ); + pxPacket->originateTimestamp.fraction = FreeRTOS_htonl( pxPacket->originateTimestamp.fraction ); + + pxPacket->receiveTimestamp.seconds = FreeRTOS_htonl( pxPacket->receiveTimestamp.seconds ); + pxPacket->receiveTimestamp.fraction = FreeRTOS_htonl( pxPacket->receiveTimestamp.fraction ); + + pxPacket->transmitTimestamp.seconds = FreeRTOS_htonl( pxPacket->transmitTimestamp.seconds ); + pxPacket->transmitTimestamp.fraction = FreeRTOS_htonl( pxPacket->transmitTimestamp.fraction ); +} +/*-----------------------------------------------------------*/ + +static void prvNTPPacketInit( ) +{ + memset (&xNTPPacket, '\0', sizeof( xNTPPacket ) ); + + xNTPPacket.flags = 0xDB; /* value 0xDB : mode 3 (client), version 3, leap indicator unknown 3 */ + xNTPPacket.poll = 10; /* 10 means 1 << 10 = 1024 seconds */ + xNTPPacket.precision = 0xFA; /* = 250 = 0.015625 seconds */ + xNTPPacket.rootDelay = 0x5D2E; /* 0x5D2E = 23854 or (23854/65535)= 0.3640 sec */ + xNTPPacket.rootDispersion = 0x0008CAC8; /* 0x0008CAC8 = 8.7912 seconds */ + + /* use the recorded NTP time */ + time_t uxSecs = FreeRTOS_time( NULL );/* apTime may be NULL, returns seconds */ + + xNTPPacket.referenceTimestamp.seconds = uxSecs; /* Current time */ + xNTPPacket.transmitTimestamp.seconds = uxSecs + 3; + + /* Transform the contents of the fields from native to big endian. */ + prvSwapFields( &xNTPPacket ); +} +/*-----------------------------------------------------------*/ + +static void prvReadTime( struct SNtpPacket * pxPacket ) +{ + FF_TimeStruct_t xTimeStruct; + time_t uxPreviousSeconds; + time_t uxPreviousMS; + + time_t uxCurrentSeconds; + time_t uxCurrentMS; + + const char *pcTimeUnit; + int32_t ilDiff; + TickType_t uxTravelTime; + + uxTravelTime = xTaskGetTickCount() - uxSendTime; + + /* Transform the contents of the fields from big to native endian. */ + prvSwapFields( pxPacket ); + + uxCurrentSeconds = pxPacket->receiveTimestamp.seconds - TIME1970; + uxCurrentMS = pxPacket->receiveTimestamp.fraction / 4294967; + uxCurrentSeconds += uxCurrentMS / 1000; + uxCurrentMS = uxCurrentMS % 1000; + + // Get the last time recorded + uxPreviousSeconds = FreeRTOS_get_secs_msec( &uxPreviousMS ); + + // Set the new time with precision in msec. */ + FreeRTOS_set_secs_msec( &uxCurrentSeconds, &uxCurrentMS ); + + if( uxCurrentSeconds >= uxPreviousSeconds ) + { + ilDiff = ( int32_t ) ( uxCurrentSeconds - uxPreviousSeconds ); + } + else + { + ilDiff = 0 - ( int32_t ) ( uxPreviousSeconds - uxCurrentSeconds ); + } + + if( ( ilDiff < -5 ) || ( ilDiff > 5 ) ) + { + /* More than 5 seconds difference. */ + pcTimeUnit = "sec"; + } + else + { + /* Less than or equal to 5 second difference. */ + pcTimeUnit = "ms"; + uint32_t ulLowest = ( uxCurrentSeconds <= uxPreviousSeconds ) ? uxCurrentSeconds : uxPreviousSeconds; + int32_t iCurMS = 1000 * ( uxCurrentSeconds - ulLowest ) + uxCurrentMS; + int32_t iPrevMS = 1000 * ( uxPreviousSeconds - ulLowest ) + uxPreviousMS; + ilDiff = iCurMS - iPrevMS; + } + uxCurrentSeconds -= iTimeZone; + + FreeRTOS_gmtime_r( &uxCurrentSeconds, &xTimeStruct ); + + /* + 378.067 [NTP client] NTP time: 9/11/2015 16:11:19.559 Diff -20 ms (289 ms) + 379.441 [NTP client] NTP time: 9/11/2015 16:11:20.933 Diff 0 ms (263 ms) + */ + + FreeRTOS_printf( ("NTP time: %d/%d/%02d %2d:%02d:%02d.%03u Diff %d %s (%lu ms)\n", + xTimeStruct.tm_mday, + xTimeStruct.tm_mon + 1, + xTimeStruct.tm_year + 1900, + xTimeStruct.tm_hour, + xTimeStruct.tm_min, + xTimeStruct.tm_sec, + ( unsigned )uxCurrentMS, + ( unsigned )ilDiff, + pcTimeUnit, + uxTravelTime ) ); + + /* Remove compiler warnings in case FreeRTOS_printf() is not used. */ + ( void ) pcTimeUnit; + ( void ) uxTravelTime; +} +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_CALLBACKS != 0 ) + + static BaseType_t xOnUDPReceive( Socket_t xSocket, void * pvData, size_t xLength, + const struct freertos_sockaddr *pxFrom, const struct freertos_sockaddr *pxDest ) + { + if( xLength >= sizeof( xNTPPacket ) ) + { + prvReadTime( ( struct SNtpPacket *)pvData ); + if( xStatus != EStatusPause ) + { + xStatus = EStatusPause; + } + } + vSignalTask(); + /* Tell the driver not to store the RX data */ + return 1; + } + /*-----------------------------------------------------------*/ + +#endif /* ipconfigUSE_CALLBACKS != 0 */ + +static void prvNTPTask( void *pvParameters ) +{ +BaseType_t xServerIndex = 3; +struct freertos_sockaddr xAddress; +#if( ipconfigUSE_CALLBACKS != 0 ) + F_TCP_UDP_Handler_t xHandler; +#endif /* ipconfigUSE_CALLBACKS != 0 */ + + xStatus = EStatusLookup; + #if( ipconfigSOCKET_HAS_USER_SEMAPHORE != 0 ) || ( ipconfigUSE_CALLBACKS != 0 ) + { + xNTPWakeupSem = xSemaphoreCreateBinary(); + } + #endif + + #if( ipconfigUSE_CALLBACKS != 0 ) + { + memset( &xHandler, '\0', sizeof( xHandler ) ); + xHandler.pxOnUDPReceive = xOnUDPReceive; + FreeRTOS_setsockopt( xUDPSocket, 0, FREERTOS_SO_UDP_RECV_HANDLER, ( void * ) &xHandler, sizeof( xHandler ) ); + } + #endif + #if( ipconfigSOCKET_HAS_USER_SEMAPHORE != 0 ) + { + FreeRTOS_setsockopt( xUDPSocket, 0, FREERTOS_SO_SET_SEMAPHORE, ( void * ) &xNTPWakeupSem, sizeof( xNTPWakeupSem ) ); + } + #endif + for( ; ; ) + { + switch( xStatus ) + { + case EStatusLookup: + if( ( ulIPAddressFound == 0ul ) || ( ulIPAddressFound == ~0ul ) ) + { + if( ++xServerIndex == sizeof( pcTimeServers ) / sizeof( pcTimeServers[ 0 ] ) ) + { + xServerIndex = 0; + } + FreeRTOS_printf( ( "Looking up server '%s'\n", pcTimeServers[ xServerIndex ] ) ); + FreeRTOS_gethostbyname_a( pcTimeServers[ xServerIndex ], vDNS_callback, (void *)NULL, 1200 ); + } + else + { + xStatus = EStatusAsking; + } + break; + + case EStatusAsking: + { + char pcBuf[16]; + + prvNTPPacketInit( ); + xAddress.sin_addr = ulIPAddressFound; + xAddress.sin_port = FreeRTOS_htons( NTP_PORT ); + + FreeRTOS_inet_ntoa( xAddress.sin_addr, pcBuf ); + FreeRTOS_printf( ( "Sending UDP message to %s:%u\n", + pcBuf, + FreeRTOS_ntohs( xAddress.sin_port ) ) ); + + uxSendTime = xTaskGetTickCount( ); + FreeRTOS_sendto( xUDPSocket, ( void * )&xNTPPacket, sizeof( xNTPPacket ), 0, &xAddress, sizeof( xAddress ) ); + } + break; + + case EStatusPause: + break; + + case EStatusFailed: + break; + } + + #if( ipconfigUSE_CALLBACKS != 0 ) + { + xSemaphoreTake( xNTPWakeupSem, 5000 ); + } + #else + { + uint32_t xAddressSize; + BaseType_t xReturned; + + xAddressSize = sizeof( xAddress ); + xReturned = FreeRTOS_recvfrom( xUDPSocket, ( void * ) cRecvBuffer, sizeof( cRecvBuffer ), 0, &xAddress, &xAddressSize ); + switch( xReturned ) + { + case 0: + case -pdFREERTOS_ERRNO_EAGAIN: + case -pdFREERTOS_ERRNO_EINTR: + break; + default: + if( xReturned < sizeof( xNTPPacket ) ) + { + FreeRTOS_printf( ( "FreeRTOS_recvfrom: returns %ld\n", xReturned ) ); + } + else + { + prvReadTime( ( struct SNtpPacket *)cRecvBuffer ); + if( xStatus != EStatusPause ) + { + xStatus = EStatusPause; + } + } + break; + } + } + #endif + } +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Plus/Demo/Common/Demo_IP_Protocols/include/FreeRTOS_FTP_commands.h b/FreeRTOS-Plus/Demo/Common/Demo_IP_Protocols/include/FreeRTOS_FTP_commands.h new file mode 100644 index 000000000..6ae2384d9 --- /dev/null +++ b/FreeRTOS-Plus/Demo/Common/Demo_IP_Protocols/include/FreeRTOS_FTP_commands.h @@ -0,0 +1,133 @@ +/* + * FreeRTOS+TCP V2.0.1 + * 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 + */ + +#ifndef __FTPCMD_H__ + +#define __FTPCMD_H__ + +#define REPL_110 "110 Restart marker reply.\r\n" +#define REPL_120 "120 Try again in 2 minutes.\r\n" +#define REPL_125 "125 Data connection already open; transfer starting.\r\n" +#define REPL_150 "150 File status okay; about to open data connection.\r\n" +#define REPL_200 "200 NOOP command successful.\r\n" +#define REPL_200_PROGRESS "200 NOOP: data transfer in progress.\r\n" +#define REPL_202 "202 Command not implemented, superfluous at this site.\r\n" +#define REPL_211 "221 System status, or system help reply.\r\n" +#define REPL_211_STATUS "221-status of %s.\r\n" +#define REPL_211_END "221 End of status.\r\n" +#define REPL_212 "212 Directory status.\r\n" +#define REPL_213 "213 File status.\r\n" +#define REPL_214 "214 Help message.\r\n" +#define REPL_214_END "214 End Help message.\r\n" +#define REPL_215 "215 %s system type.\r\n" +#define REPL_220 "220 Service ready for new user.\r\n" +#define REPL_221 "221 Service closing control connection.\r\n" +#define REPL_225 "225 Data connection open; no transfer in progress.\r\n" +#define REPL_226 "226 Closing data connection.\r\n" +#define REPL_227 "227 Entering Passive Mode (%s,%s,%s,%s,%s,%s).\r\n" +#define REPL_227_D "227 Entering Passive Mode (%u,%u,%u,%u,%u,%u).\r\n" +#define REPL_230 "230 User logged in, proceed.\r\n" +#define REPL_250 "250 Requested file action okay, completed.\r\n" +#define REPL_257 "257 %s created.\r\n" +// #define REPL_257_PWD "257 \"%s\" is current working dir.\r\n" +#define REPL_257_PWD "257 \"%s\"\r\n" +#define REPL_331 "331 Only anonymous user is accepted.\r\n" +#define REPL_331_ANON "331 Anonymous login okay\r\n" +#define REPL_332 "332 Need account for login.\r\n" +#define REPL_350 "350 Requested file action pending further information.\r\n" +#define REPL_421 "421 Service not available, closing control connection.\r\n" +#define REPL_425 "425 Can't open data connection.\r\n" +#define REPL_426 "426 Connection closed; transfer aborted.\r\n" +#define REPL_450 "450 Requested file action not taken.\r\n" +#define REPL_451 "451 Requested action aborted. Local error in processing.\r\n" +#define REPL_452 "452 Requested action not taken.\r\n" +#define REPL_500 "500 Syntax error, command unrecognized.\r\n" +#define REPL_501 "501 Syntax error in parameters or arguments.\r\n" +#define REPL_502 "502 Command not implemented.\r\n" +#define REPL_503 "503 Bad sequence of commands.\r\n" +#define REPL_504 "504 Command not implemented for that parameter.\r\n" +#define REPL_530 "530 Not logged in.\r\n" +#define REPL_532 "532 Need account for storing files.\r\n" +#define REPL_550 "550 Requested action not taken.\r\n" +#define REPL_551 "551 Requested action aborted. Page type unknown.\r\n" +#define REPL_552 "552 Requested file action aborted.\r\n" +#define REPL_553 "553 Requested action not taken.\r\n" +#define REPL_553_READ_ONLY "553 Read-only file-system.\r\n" + +enum EFTPCommand { + ECMD_USER, + ECMD_PASS, + ECMD_ACCT, + ECMD_CWD, + ECMD_CDUP, + ECMD_SMNT, + ECMD_QUIT, + ECMD_REIN, + ECMD_PORT, + ECMD_PASV, + ECMD_TYPE, + ECMD_STRU, + ECMD_MODE, + ECMD_RETR, + ECMD_STOR, + ECMD_STOU, + ECMD_APPE, + ECMD_ALLO, + ECMD_REST, + ECMD_RNFR, + ECMD_RNTO, + ECMD_ABOR, + ECMD_SIZE, + ECMD_MDTM, + ECMD_DELE, + ECMD_RMD, + ECMD_MKD, + ECMD_PWD, + ECMD_LIST, + ECMD_NLST, + ECMD_SITE, + ECMD_SYST, + ECMD_FEAT, + ECMD_STAT, + ECMD_HELP, + ECMD_NOOP, + ECMD_EMPTY, + ECMD_CLOSE, + ECMD_UNKNOWN, +}; + +typedef struct xFTP_COMMAND { + BaseType_t xCommandLength; + const char pcCommandName[7]; + const unsigned char ucCommandType; + const unsigned char checkLogin; + const unsigned char checkNullArg; +} FTPCommand_t; + +#define FTP_CMD_COUNT (ECMD_UNKNOWN+1) + +extern const FTPCommand_t xFTPCommands[ FTP_CMD_COUNT ]; + +#endif // __FTPCMD_H__ diff --git a/FreeRTOS-Plus/Demo/Common/Demo_IP_Protocols/include/FreeRTOS_HTTP_commands.h b/FreeRTOS-Plus/Demo/Common/Demo_IP_Protocols/include/FreeRTOS_HTTP_commands.h new file mode 100644 index 000000000..75eaf5d9f --- /dev/null +++ b/FreeRTOS-Plus/Demo/Common/Demo_IP_Protocols/include/FreeRTOS_HTTP_commands.h @@ -0,0 +1,67 @@ +/* + * FreeRTOS+TCP V2.0.3 + * 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 + */ +#ifndef FREERTOS_HTTP_COMMANDS_H +#define FREERTOS_HTTP_COMMANDS_H + +enum { + WEB_REPLY_OK = 200, + WEB_NO_CONTENT = 204, + WEB_BAD_REQUEST = 400, + WEB_UNAUTHORIZED = 401, + WEB_NOT_FOUND = 404, + WEB_GONE = 410, + WEB_PRECONDITION_FAILED = 412, + WEB_INTERNAL_SERVER_ERROR = 500, +}; + +enum EWebCommand { + ECMD_GET, + ECMD_HEAD, + ECMD_POST, + ECMD_PUT, + ECMD_DELETE, + ECMD_TRACE, + ECMD_OPTIONS, + ECMD_CONNECT, + ECMD_PATCH, + ECMD_UNK, +}; + +struct xWEB_COMMAND +{ + BaseType_t xCommandLength; + const char *pcCommandName; + const unsigned char ucCommandType; +}; + +#define WEB_CMD_COUNT (ECMD_UNK+1) + +extern const struct xWEB_COMMAND xWebCommands[WEB_CMD_COUNT]; + +extern const char *webCodename (int aCode); + +#endif /* FREERTOS_HTTP_COMMANDS_H */ + + diff --git a/FreeRTOS-Plus/Demo/Common/Demo_IP_Protocols/include/FreeRTOS_TCP_server.h b/FreeRTOS-Plus/Demo/Common/Demo_IP_Protocols/include/FreeRTOS_TCP_server.h new file mode 100644 index 000000000..d8140ce82 --- /dev/null +++ b/FreeRTOS-Plus/Demo/Common/Demo_IP_Protocols/include/FreeRTOS_TCP_server.h @@ -0,0 +1,125 @@ +/* + * FreeRTOS+TCP V2.0.3 + * 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 + */ + +/* + Some code which is common to TCP servers like HTTP en FTP +*/ + +#ifndef FREERTOS_TCP_SERVER_H +#define FREERTOS_TCP_SERVER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef FTP_SERVER_USES_RELATIVE_DIRECTORY + #define FTP_SERVER_USES_RELATIVE_DIRECTORY 0 +#endif + +enum eSERVER_TYPE +{ + eSERVER_NONE, + eSERVER_HTTP, + eSERVER_FTP, +}; + +struct xFTP_CLIENT; + +#if( ipconfigFTP_HAS_RECEIVED_HOOK != 0 ) + extern void vApplicationFTPReceivedHook( const char *pcFileName, uint32_t ulSize, struct xFTP_CLIENT *pxFTPClient ); + extern void vFTPReplyMessage( struct xFTP_CLIENT *pxFTPClient, const char *pcMessage ); +#endif /* ipconfigFTP_HAS_RECEIVED_HOOK != 0 */ + +#if( ipconfigFTP_HAS_USER_PASSWORD_HOOK != 0 ) + /* + * Function is called when a user name has been submitted. + * The function may return a string such as: "331 Please enter your password" + * or return NULL to use the default reply. + */ + extern const char *pcApplicationFTPUserHook( const char *pcUserName ); +#endif /* ipconfigFTP_HAS_USER_PASSWORD_HOOK */ + +#if( ipconfigFTP_HAS_USER_PASSWORD_HOOK != 0 ) + /* + * Function is called when a password was received. + * Return positive value to allow the user + */ + extern BaseType_t xApplicationFTPPasswordHook( const char *pcUserName, const char *pcPassword ); +#endif /* ipconfigFTP_HAS_USER_PASSWORD_HOOK */ + +#if( ipconfigFTP_HAS_USER_PROPERTIES_HOOK != 0 ) + /* + * The FTP server is asking for user-specific properties + */ + typedef struct + { + uint16_t usPortNumber; /* For reference only. Host-endian. */ + const char *pcRootDir; + BaseType_t xReadOnly; + } + FTPUserProperties_t; + extern void vApplicationFTPUserPropertiesHook( const char *pcUserName, FTPUserProperties_t *pxProperties ); +#endif /* ipconfigFTP_HAS_USER_PASSWORD_HOOK */ + +#if( ipconfigHTTP_HAS_HANDLE_REQUEST_HOOK != 0 ) + /* + * A GET request is received containing a special character, + * usually a question mark. + * const char *pcURLData; // A request, e.g. "/request?limit=75" + * char *pcBuffer; // Here the answer can be written + * size_t uxBufferLength; // Size of the buffer + * + */ + extern size_t uxApplicationHTTPHandleRequestHook( const char *pcURLData, char *pcBuffer, size_t uxBufferLength ); +#endif /* ipconfigHTTP_HAS_HANDLE_REQUEST_HOOK */ + +struct xSERVER_CONFIG +{ + enum eSERVER_TYPE eType; /* eSERVER_HTTP | eSERVER_FTP */ + BaseType_t xPortNumber; /* e.g. 80, 8080, 21 */ + BaseType_t xBackLog; /* e.g. 10, maximum number of connected TCP clients */ + const char * const pcRootDir; /* Treat this directory as the root directory */ +}; + +struct xTCP_SERVER; +typedef struct xTCP_SERVER TCPServer_t; + +TCPServer_t *FreeRTOS_CreateTCPServer( const struct xSERVER_CONFIG *pxConfigs, BaseType_t xCount ); +void FreeRTOS_TCPServerWork( TCPServer_t *pxServer, TickType_t xBlockingTime ); + +#if( ipconfigSUPPORT_SIGNALS != 0 ) + /* FreeRTOS_TCPServerWork() calls select(). + The two functions below provide a possibility to interrupt + the call to select(). After the interruption, resume + by calling FreeRTOS_TCPServerWork() again. */ + BaseType_t FreeRTOS_TCPServerSignal( TCPServer_t *pxServer ); + BaseType_t FreeRTOS_TCPServerSignalFromISR( TCPServer_t *pxServer, BaseType_t *pxHigherPriorityTaskWoken ); +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* FREERTOS_TCP_SERVER_H */ diff --git a/FreeRTOS-Plus/Demo/Common/Demo_IP_Protocols/include/FreeRTOS_server_private.h b/FreeRTOS-Plus/Demo/Common/Demo_IP_Protocols/include/FreeRTOS_server_private.h new file mode 100644 index 000000000..73768040e --- /dev/null +++ b/FreeRTOS-Plus/Demo/Common/Demo_IP_Protocols/include/FreeRTOS_server_private.h @@ -0,0 +1,185 @@ +/* + * FreeRTOS+TCP V2.0.3 + * 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 + */ + + /* + Some code which is common to TCP servers like HTTP and FTP +*/ + +#ifndef FREERTOS_SERVER_PRIVATE_H +#define FREERTOS_SERVER_PRIVATE_H + +#define FREERTOS_NO_SOCKET NULL + +/* FreeRTOS+FAT */ +#include "ff_stdio.h" + +/* Each HTTP server has 1, at most 2 sockets */ +#define HTTP_SOCKET_COUNT 2 + +/* + * ipconfigTCP_COMMAND_BUFFER_SIZE sets the size of: + * pcCommandBuffer': a buffer to receive and send TCP commands + * + * ipconfigTCP_FILE_BUFFER_SIZE sets the size of: + * pcFileBuffer' : a buffer to access the file system: read or write data. + * + * The buffers are both used for FTP as well as HTTP. + */ + +#ifndef ipconfigTCP_COMMAND_BUFFER_SIZE + #define ipconfigTCP_COMMAND_BUFFER_SIZE ( 2048 ) +#endif + +#ifndef ipconfigTCP_FILE_BUFFER_SIZE + #define ipconfigTCP_FILE_BUFFER_SIZE ( 2048 ) +#endif + +struct xTCP_CLIENT; + +typedef BaseType_t ( * FTCPWorkFunction ) ( struct xTCP_CLIENT * /* pxClient */ ); +typedef void ( * FTCPDeleteFunction ) ( struct xTCP_CLIENT * /* pxClient */ ); + +#define TCP_CLIENT_FIELDS \ + enum eSERVER_TYPE eType; \ + struct xTCP_SERVER *pxParent; \ + Socket_t xSocket; \ + const char *pcRootDir; \ + FTCPWorkFunction fWorkFunction; \ + FTCPDeleteFunction fDeleteFunction; \ + struct xTCP_CLIENT *pxNextClient + +typedef struct xTCP_CLIENT +{ + /* This define contains fields which must come first within each of the client structs */ + TCP_CLIENT_FIELDS; + /* --- Keep at the top --- */ + +} TCPClient_t; + +struct xHTTP_CLIENT +{ + /* This define contains fields which must come first within each of the client structs */ + TCP_CLIENT_FIELDS; + /* --- Keep at the top --- */ + + const char *pcUrlData; + const char *pcRestData; + char pcCurrentFilename[ ffconfigMAX_FILENAME ]; + size_t uxBytesLeft; + FF_FILE *pxFileHandle; + union { + struct { + uint32_t + bReplySent : 1; + }; + uint32_t ulFlags; + } bits; +}; + +typedef struct xHTTP_CLIENT HTTPClient_t; + +struct xFTP_CLIENT +{ + /* This define contains fields which must come first within each of the client structs */ + TCP_CLIENT_FIELDS; + /* --- Keep at the top --- */ + + uint32_t ulRestartOffset; + uint32_t ulRecvBytes; + size_t uxBytesLeft; /* Bytes left to send */ + uint32_t ulClientIP; + TickType_t xStartTime; + uint16_t usClientPort; + Socket_t xTransferSocket; + BaseType_t xTransType; + BaseType_t xDirCount; + FF_FindData_t xFindData; + FF_FILE *pxReadHandle; + FF_FILE *pxWriteHandle; + char pcCurrentDir[ ffconfigMAX_FILENAME ]; + char pcFileName[ ffconfigMAX_FILENAME ]; + char pcConnectionAck[ 128 ]; + char pcClientAck[ 128 ]; + union { + struct { + uint32_t + bHelloSent : 1, + bLoggedIn : 1, + bStatusUser : 1, + bInRename : 1, + bReadOnly : 1; + }; + uint32_t ulFTPFlags; + } bits; + union { + struct { + uint32_t + bIsListen : 1, /* pdTRUE for passive data connections (using list()). */ + bDirHasEntry : 1, /* pdTRUE if ff_findfirst() was successful. */ + bClientConnected : 1, /* pdTRUE after connect() or accept() has succeeded. */ + bEmptyFile : 1, /* pdTRUE if a connection-without-data was received. */ + bHadError : 1; /* pdTRUE if a transfer got aborted because of an error. */ + }; + uint32_t ulConnFlags; + } bits1; +}; + +typedef struct xFTP_CLIENT FTPClient_t; + +BaseType_t xHTTPClientWork( TCPClient_t *pxClient ); +BaseType_t xFTPClientWork( TCPClient_t *pxClient ); + +void vHTTPClientDelete( TCPClient_t *pxClient ); +void vFTPClientDelete( TCPClient_t *pxClient ); + +BaseType_t xMakeAbsolute( struct xFTP_CLIENT *pxClient, char *pcBuffer, BaseType_t xBufferLength, const char *pcFileName ); +BaseType_t xMakeRelative( FTPClient_t *pxClient, char *pcBuffer, BaseType_t xBufferLength, const char *pcFileName ); + +struct xTCP_SERVER +{ + SocketSet_t xSocketSet; + /* A buffer to receive and send TCP commands, either HTTP of FTP. */ + char pcCommandBuffer[ ipconfigTCP_COMMAND_BUFFER_SIZE ]; + /* A buffer to access the file system: read or write data. */ + char pcFileBuffer[ ipconfigTCP_FILE_BUFFER_SIZE ]; + + #if( ipconfigUSE_FTP != 0 ) + char pcNewDir[ ffconfigMAX_FILENAME ]; + #endif + #if( ipconfigUSE_HTTP != 0 ) + char pcContentsType[40]; /* Space for the msg: "text/javascript" */ + char pcExtraContents[40]; /* Space for the msg: "Content-Length: 346500" */ + #endif + BaseType_t xServerCount; + TCPClient_t *pxClients; + struct xSERVER + { + enum eSERVER_TYPE eType; /* eSERVER_HTTP | eSERVER_FTP */ + const char *pcRootDir; + Socket_t xSocket; + } xServers[ 1 ]; +}; + +#endif /* FREERTOS_SERVER_PRIVATE_H */ diff --git a/FreeRTOS-Plus/Demo/Common/Demo_IP_Protocols/include/NTPClient.h b/FreeRTOS-Plus/Demo/Common/Demo_IP_Protocols/include/NTPClient.h new file mode 100644 index 000000000..813539e6e --- /dev/null +++ b/FreeRTOS-Plus/Demo/Common/Demo_IP_Protocols/include/NTPClient.h @@ -0,0 +1,71 @@ +// +// ntpClient.h +// + +#ifndef __NTPCLIENT_H__ + +#define __NTPCLIENT_H__ + +#define NTP_PORT 123 + +typedef uint32_t quint32; +typedef int32_t qint32; +typedef uint8_t quint8; +typedef int8_t qint8; + +typedef union _SNtpFlags SNtpFlags; + +/** + * 64-bit NTP timestamp. + */ +struct __attribute__ ((__packed__)) _SNtpTimestamp { + /** Number of seconds passed since Jan 1 1900, in big-endian format. */ + quint32 seconds; + + /** Fractional time part, in 1/0xFFFFFFFFs of a second. */ + quint32 fraction; +}; + +typedef struct _SNtpTimestamp SNtpTimestamp; +/** + * Mandatory part of an NTP packet + */ +struct SNtpPacket { + /** Flags. */ + unsigned char flags; // value 0xDB : mode 3 (client), version 3, leap indicator unknown 3 + + /** Stratum of the clock. */ + quint8 stratum; // value 0 : unspecified + + /** Maximum interval between successive messages, in log2 seconds. Note that the value is signed. */ + qint8 poll; // 10 means 1 << 10 = 1024 seconds + + /** Precision of the clock, in log2 seconds. Note that the value is signed. */ + qint8 precision; // 0xFA = 250 = 0.015625 seconds + + /** Round trip time to the primary reference source, in NTP short format. */ + qint32 rootDelay; // 0x5D2E = 23854 or (23854/65535)= 0.3640 sec + + /** Nominal error relative to the primary reference source. */ + qint32 rootDispersion; // 0x0008 CAC8 = 8.7912 seconds + + /** Reference identifier (either a 4 character string or an IP address). */ + qint8 referenceID[4]; // or just 0000 + + /** The time at which the clock was last set or corrected. */ + SNtpTimestamp referenceTimestamp; // Current time + + /** The time at which the request departed the client for the server. */ + SNtpTimestamp originateTimestamp; // Keep 0 + + /** The time at which the request arrived at the server. */ + SNtpTimestamp receiveTimestamp; // Keep 0 + + /** The time at which the reply departed the server for client. */ + SNtpTimestamp transmitTimestamp; +}; + +/* Add this number to get secs since 1-1-1900 */ +#define TIME1970 2208988800UL + +#endif // __NTPCLIENT_H__ diff --git a/FreeRTOS-Plus/Demo/Common/Demo_IP_Protocols/include/NTPDemo.h b/FreeRTOS-Plus/Demo/Common/Demo_IP_Protocols/include/NTPDemo.h new file mode 100644 index 000000000..e75fb76aa --- /dev/null +++ b/FreeRTOS-Plus/Demo/Common/Demo_IP_Protocols/include/NTPDemo.h @@ -0,0 +1,11 @@ +/* + * A simple demo for NTP using FreeRTOS+TCP + */ + +#ifndef NTPDEMO_H + +#define NTPDEMO_H + +void vStartNTPTask( uint16_t usTaskStackSize, UBaseType_t uxTaskPriority ); + +#endif \ No newline at end of file diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_ARP.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_ARP.c index 710093a90..b31b76894 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_ARP.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_ARP.c @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.3 + * FreeRTOS+TCP V2.0.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 @@ -211,7 +211,10 @@ uint32_t ulTargetProtocolAddress, ulSenderProtocolAddress; void vARPRefreshCacheEntry( const MACAddress_t * pxMACAddress, const uint32_t ulIPAddress ) { -BaseType_t x, xIpEntry = -1, xMacEntry = -1, xUseEntry = 0; +BaseType_t x = 0; +BaseType_t xIpEntry = -1; +BaseType_t xMacEntry = -1; +BaseType_t xUseEntry = 0; uint8_t ucMinAgeFound = 0U; #if( ipconfigARP_STORES_REMOTE_ADDRESSES == 0 ) @@ -599,7 +602,7 @@ ARPPacket_t *pxARPPacket; xARPHeader.usOperation; xARPHeader.xTargetHardwareAddress; */ - memcpy( ( void * ) &( pxARPPacket->xEthernetHeader ), ( void * ) xDefaultPartARPPacketHeader, sizeof( xDefaultPartARPPacketHeader ) ); + memcpy( ( void * ) pxARPPacket, ( void * ) xDefaultPartARPPacketHeader, sizeof( xDefaultPartARPPacketHeader ) ); memcpy( ( void * ) pxARPPacket->xEthernetHeader.xSourceAddress.ucBytes , ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES ); memcpy( ( void * ) pxARPPacket->xARPHeader.xSenderHardwareAddress.ucBytes, ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES ); diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_DHCP.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_DHCP.c index 8ce9e8e92..eef8ec848 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_DHCP.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_DHCP.c @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.3 + * FreeRTOS+TCP V2.0.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 @@ -63,17 +63,17 @@ #endif /* Codes of interest found in the DHCP options field. */ -#define dhcpIPv4_ZERO_PAD_OPTION_CODE ( 0u ) -#define dhcpIPv4_SUBNET_MASK_OPTION_CODE ( 1u ) -#define dhcpIPv4_GATEWAY_OPTION_CODE ( 3u ) -#define dhcpIPv4_DNS_SERVER_OPTIONS_CODE ( 6u ) -#define dhcpIPv4_DNS_HOSTNAME_OPTIONS_CODE ( 12u ) -#define dhcpIPv4_REQUEST_IP_ADDRESS_OPTION_CODE ( 50u ) -#define dhcpIPv4_LEASE_TIME_OPTION_CODE ( 51u ) -#define dhcpIPv4_MESSAGE_TYPE_OPTION_CODE ( 53u ) -#define dhcpIPv4_SERVER_IP_ADDRESS_OPTION_CODE ( 54u ) -#define dhcpIPv4_PARAMETER_REQUEST_OPTION_CODE ( 55u ) -#define dhcpIPv4_CLIENT_IDENTIFIER_OPTION_CODE ( 61u ) +#define dhcpZERO_PAD_OPTION_CODE ( 0u ) +#define dhcpSUBNET_MASK_OPTION_CODE ( 1u ) +#define dhcpGATEWAY_OPTION_CODE ( 3u ) +#define dhcpDNS_SERVER_OPTIONS_CODE ( 6u ) +#define dhcpDNS_HOSTNAME_OPTIONS_CODE ( 12u ) +#define dhcpREQUEST_IP_ADDRESS_OPTION_CODE ( 50u ) +#define dhcpLEASE_TIME_OPTION_CODE ( 51u ) +#define dhcpMESSAGE_TYPE_OPTION_CODE ( 53u ) +#define dhcpSERVER_IP_ADDRESS_OPTION_CODE ( 54u ) +#define dhcpPARAMETER_REQUEST_OPTION_CODE ( 55u ) +#define dhcpCLIENT_IDENTIFIER_OPTION_CODE ( 61u ) /* The four DHCP message types of interest. */ #define dhcpMESSAGE_TYPE_DISCOVER ( 1 ) @@ -113,9 +113,7 @@ to ensure the walk has not gone past the end of the valid options. 2 bytes is made up of the length byte, and minimum one byte value. */ #define dhcpMAX_OPTION_LENGTH_OF_INTEREST ( 2L ) -/* Standard DHCP port numbers and magic cookie value. -DHCPv4 uses UDP port number 68 for clients and port number 67 for servers. -*/ +/* Standard DHCP port numbers and magic cookie value. */ #if( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN ) #define dhcpCLIENT_PORT 0x4400u #define dhcpSERVER_PORT 0x4300u @@ -361,11 +359,19 @@ BaseType_t xGivingUp = pdFALSE; if( xDHCPData.xDHCPTxPeriod <= ipconfigMAXIMUM_DISCOVER_TX_PERIOD ) { - xDHCPData.ulTransactionId++; - xDHCPData.xDHCPTxTime = xTaskGetTickCount(); - xDHCPData.xUseBroadcast = !xDHCPData.xUseBroadcast; - prvSendDHCPDiscover( ); - FreeRTOS_debug_printf( ( "vDHCPProcess: timeout %lu ticks\n", xDHCPData.xDHCPTxPeriod ) ); + xDHCPData.ulTransactionId = ipconfigRAND32( ); + + if( 0 != xDHCPData.ulTransactionId ) + { + xDHCPData.xDHCPTxTime = xTaskGetTickCount( ); + xDHCPData.xUseBroadcast = !xDHCPData.xUseBroadcast; + prvSendDHCPDiscover( ); + FreeRTOS_debug_printf( ( "vDHCPProcess: timeout %lu ticks\n", xDHCPData.xDHCPTxPeriod ) ); + } + else + { + FreeRTOS_debug_printf( ( "vDHCPProcess: failed to generate a random Transaction ID\n" ) ); + } } else { @@ -517,7 +523,7 @@ BaseType_t xGivingUp = pdFALSE; { /* xGivingUp became true either because of a time-out, or because xApplicationDHCPHook() returned another value than 'eDHCPContinue', - meaning that the conversion is cancelled from here. */ + meaning that the conversion is canceled from here. */ /* Revert to static IP address. */ taskENTER_CRITICAL(); @@ -585,29 +591,24 @@ TickType_t xTimeoutTime = ( TickType_t ) 0; static void prvInitialiseDHCP( void ) { - /* Initialise the parameters that will be set by the DHCP process. */ - if( xDHCPData.ulTransactionId == 0ul ) - { - xDHCPData.ulTransactionId = ipconfigRAND32(); - } - else - { - xDHCPData.ulTransactionId++; - } - - /* Check for random number generator API failure. */ - if( 0 != xDHCPData.ulTransactionId ) - { - xDHCPData.xUseBroadcast = 0; - xDHCPData.ulOfferedIPAddress = 0UL; - xDHCPData.ulDHCPServerAddress = 0UL; - xDHCPData.xDHCPTxPeriod = dhcpINITIAL_DHCP_TX_PERIOD; - - /* Create the DHCP socket if it has not already been created. */ - prvCreateDHCPSocket(); - FreeRTOS_debug_printf( ( "prvInitialiseDHCP: start after %lu ticks\n", dhcpINITIAL_TIMER_PERIOD ) ); - vIPReloadDHCPTimer( dhcpINITIAL_TIMER_PERIOD ); - } + /* Initialise the parameters that will be set by the DHCP process. Per + https://www.ietf.org/rfc/rfc2131.txt, Transaction ID should be a random + value chosen by the client. */ + xDHCPData.ulTransactionId = ipconfigRAND32(); + + /* Check for random number generator API failure. */ + if( 0 != xDHCPData.ulTransactionId ) + { + xDHCPData.xUseBroadcast = 0; + xDHCPData.ulOfferedIPAddress = 0UL; + xDHCPData.ulDHCPServerAddress = 0UL; + xDHCPData.xDHCPTxPeriod = dhcpINITIAL_DHCP_TX_PERIOD; + + /* Create the DHCP socket if it has not already been created. */ + prvCreateDHCPSocket(); + FreeRTOS_debug_printf( ( "prvInitialiseDHCP: start after %lu ticks\n", dhcpINITIAL_TIMER_PERIOD ) ); + vIPReloadDHCPTimer( dhcpINITIAL_TIMER_PERIOD ); + } } /*-----------------------------------------------------------*/ @@ -631,11 +632,14 @@ const uint32_t ulMandatoryOptions = 2ul; /* DHCP server address, and the correct pxDHCPMessage = ( DHCPMessage_t * ) ( pucUDPPayload ); /* Sanity check. */ - if( ( pxDHCPMessage->ulDHCPCookie == ( uint32_t ) dhcpCOOKIE ) && + if( ( lBytes >= sizeof( DHCPMessage_t ) ) && + ( pxDHCPMessage->ulDHCPCookie == ( uint32_t ) dhcpCOOKIE ) && ( pxDHCPMessage->ucOpcode == ( uint8_t ) dhcpREPLY_OPCODE ) && ( pxDHCPMessage->ulTransactionID == FreeRTOS_htonl( xDHCPData.ulTransactionId ) ) ) { - if( memcmp( ( void * ) &( pxDHCPMessage->ucClientHardwareAddress ), ( void * ) ipLOCAL_MAC_ADDRESS, sizeof( MACAddress_t ) ) == 0 ) + if( memcmp( ( void * ) &( pxDHCPMessage->ucClientHardwareAddress ), + ( void * ) ipLOCAL_MAC_ADDRESS, + sizeof( MACAddress_t ) ) == 0 ) { /* None of the essential options have been processed yet. */ ulProcessed = 0ul; @@ -648,28 +652,52 @@ const uint32_t ulMandatoryOptions = 2ul; /* DHCP server address, and the correct while( pucByte < pucLastByte ) { ucOptionCode = pucByte[ 0 ]; - if( ucOptionCode == ( uint8_t ) dhcpOPTION_END_BYTE ) + if( ucOptionCode == dhcpOPTION_END_BYTE ) { /* Ready, the last byte has been seen. */ break; } - if( ucOptionCode == ( uint8_t ) dhcpIPv4_ZERO_PAD_OPTION_CODE ) + if( ucOptionCode == dhcpZERO_PAD_OPTION_CODE ) { /* The value zero is used as a pad byte, it is not followed by a length byte. */ pucByte += 1; continue; } - ucLength = pucByte[ 1 ]; - pucByte += 2; - /* In most cases, a 4-byte network-endian parameter follows, - just get it once here and use later */ - memcpy( ( void * ) &( ulParameter ), ( void * ) pucByte, ( size_t ) sizeof( ulParameter ) ); + /* Stop if the response is malformed. */ + if( pucByte < pucLastByte - 1 ) + { + ucLength = pucByte[ 1 ]; + pucByte += 2; + + if( pucByte >= pucLastByte - ucLength ) + { + break; + } + } + else + { + break; + } + /* In most cases, a 4-byte network-endian parameter follows, + just get it once here and use later. */ + if( ucLength >= sizeof( ulParameter ) ) + { + memcpy( ( void * ) &( ulParameter ), + ( void * ) pucByte, + ( size_t ) sizeof( ulParameter ) ); + } + else + { + ulParameter = 0; + } + + /* Option-specific handling. */ switch( ucOptionCode ) { - case dhcpIPv4_MESSAGE_TYPE_OPTION_CODE : + case dhcpMESSAGE_TYPE_OPTION_CODE : if( *pucByte == ( uint8_t ) xExpectedMessageType ) { @@ -691,7 +719,7 @@ const uint32_t ulMandatoryOptions = 2ul; /* DHCP server address, and the correct } break; - case dhcpIPv4_SUBNET_MASK_OPTION_CODE : + case dhcpSUBNET_MASK_OPTION_CODE : if( ucLength == sizeof( uint32_t ) ) { @@ -699,9 +727,9 @@ const uint32_t ulMandatoryOptions = 2ul; /* DHCP server address, and the correct } break; - case dhcpIPv4_GATEWAY_OPTION_CODE : - /* The DHCP server may send more than 1 gateway addresses. */ - if( ucLength >= sizeof( uint32_t ) ) + case dhcpGATEWAY_OPTION_CODE : + + if( ucLength == sizeof( uint32_t ) ) { /* ulProcessed is not incremented in this case because the gateway is not essential. */ @@ -709,7 +737,7 @@ const uint32_t ulMandatoryOptions = 2ul; /* DHCP server address, and the correct } break; - case dhcpIPv4_DNS_SERVER_OPTIONS_CODE : + case dhcpDNS_SERVER_OPTIONS_CODE : /* ulProcessed is not incremented in this case because the DNS server is not essential. Only the @@ -717,7 +745,7 @@ const uint32_t ulMandatoryOptions = 2ul; /* DHCP server address, and the correct xNetworkAddressing.ulDNSServerAddress = ulParameter; break; - case dhcpIPv4_SERVER_IP_ADDRESS_OPTION_CODE : + case dhcpSERVER_IP_ADDRESS_OPTION_CODE : if( ucLength == sizeof( uint32_t ) ) { @@ -738,7 +766,7 @@ const uint32_t ulMandatoryOptions = 2ul; /* DHCP server address, and the correct } break; - case dhcpIPv4_LEASE_TIME_OPTION_CODE : + case dhcpLEASE_TIME_OPTION_CODE : if( ucLength == sizeof( xDHCPData.ulLeaseTime ) ) { @@ -789,7 +817,7 @@ const uint32_t ulMandatoryOptions = 2ul; /* DHCP server address, and the correct } FreeRTOS_ReleaseUDPPayloadBuffer( ( void * ) pucUDPPayload ); - } /* if( lBytes > 0 ) */ + } return xReturn; } @@ -825,9 +853,6 @@ uint8_t *pucUDPPayloadBuffer; pxDHCPMessage->ucOpcode = ( uint8_t ) xOpcode; pxDHCPMessage->ucAddressType = ( uint8_t ) dhcpADDRESS_TYPE_ETHERNET; pxDHCPMessage->ucAddressLength = ( uint8_t ) dhcpETHERNET_ADDRESS_LENGTH; - - /* ulTransactionID doesn't really need a htonl() translation, but when DHCP - times out, it is nicer to see an increasing number in this ID field */ pxDHCPMessage->ulTransactionID = FreeRTOS_htonl( xDHCPData.ulTransactionId ); pxDHCPMessage->ulDHCPCookie = ( uint32_t ) dhcpCOOKIE; if( xDHCPData.xUseBroadcast != pdFALSE ) @@ -851,7 +876,7 @@ uint8_t *pucUDPPayloadBuffer; /* Point to where the OPTION_END was stored to add data. */ pucPtr = &( pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET + ( *pxOptionsArraySize - 1 ) ] ); - pucPtr[ 0 ] = dhcpIPv4_DNS_HOSTNAME_OPTIONS_CODE; + pucPtr[ 0 ] = dhcpDNS_HOSTNAME_OPTIONS_CODE; pucPtr[ 1 ] = ( uint8_t ) xNameLength; memcpy( ( void *) ( pucPtr + 2 ), pucHostName, xNameLength ); pucPtr[ 2 + xNameLength ] = dhcpOPTION_END_BYTE; @@ -880,15 +905,15 @@ static const uint8_t ucDHCPRequestOptions[] = /* Do not change the ordering without also changing dhcpCLIENT_IDENTIFIER_OFFSET, dhcpREQUESTED_IP_ADDRESS_OFFSET and dhcpDHCP_SERVER_IP_ADDRESS_OFFSET. */ - dhcpIPv4_MESSAGE_TYPE_OPTION_CODE, 1, dhcpMESSAGE_TYPE_REQUEST, /* Message type option. */ - dhcpIPv4_CLIENT_IDENTIFIER_OPTION_CODE, 6, 0, 0, 0, 0, 0, 0, /* Client identifier. */ - dhcpIPv4_REQUEST_IP_ADDRESS_OPTION_CODE, 4, 0, 0, 0, 0, /* The IP address being requested. */ - dhcpIPv4_SERVER_IP_ADDRESS_OPTION_CODE, 4, 0, 0, 0, 0, /* The IP address of the DHCP server. */ + dhcpMESSAGE_TYPE_OPTION_CODE, 1, dhcpMESSAGE_TYPE_REQUEST, /* Message type option. */ + dhcpCLIENT_IDENTIFIER_OPTION_CODE, 6, 0, 0, 0, 0, 0, 0, /* Client identifier. */ + dhcpREQUEST_IP_ADDRESS_OPTION_CODE, 4, 0, 0, 0, 0, /* The IP address being requested. */ + dhcpSERVER_IP_ADDRESS_OPTION_CODE, 4, 0, 0, 0, 0, /* The IP address of the DHCP server. */ dhcpOPTION_END_BYTE }; size_t xOptionsLength = sizeof( ucDHCPRequestOptions ); - pucUDPPayloadBuffer = prvCreatePartDHCPMessage( &xAddress, ( uint8_t ) dhcpREQUEST_OPCODE, ucDHCPRequestOptions, &xOptionsLength ); + pucUDPPayloadBuffer = prvCreatePartDHCPMessage( &xAddress, dhcpREQUEST_OPCODE, ucDHCPRequestOptions, &xOptionsLength ); /* Copy in the IP address being requested. */ memcpy( ( void * ) &( pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET + dhcpREQUESTED_IP_ADDRESS_OFFSET ] ), @@ -917,14 +942,14 @@ struct freertos_sockaddr xAddress; static const uint8_t ucDHCPDiscoverOptions[] = { /* Do not change the ordering without also changing dhcpCLIENT_IDENTIFIER_OFFSET. */ - dhcpIPv4_MESSAGE_TYPE_OPTION_CODE, 1, dhcpMESSAGE_TYPE_DISCOVER, /* Message type option. */ - dhcpIPv4_CLIENT_IDENTIFIER_OPTION_CODE, 6, 0, 0, 0, 0, 0, 0, /* Client identifier. */ - dhcpIPv4_PARAMETER_REQUEST_OPTION_CODE, 3, dhcpIPv4_SUBNET_MASK_OPTION_CODE, dhcpIPv4_GATEWAY_OPTION_CODE, dhcpIPv4_DNS_SERVER_OPTIONS_CODE, /* Parameter request option. */ + dhcpMESSAGE_TYPE_OPTION_CODE, 1, dhcpMESSAGE_TYPE_DISCOVER, /* Message type option. */ + dhcpCLIENT_IDENTIFIER_OPTION_CODE, 6, 0, 0, 0, 0, 0, 0, /* Client identifier. */ + dhcpPARAMETER_REQUEST_OPTION_CODE, 3, dhcpSUBNET_MASK_OPTION_CODE, dhcpGATEWAY_OPTION_CODE, dhcpDNS_SERVER_OPTIONS_CODE, /* Parameter request option. */ dhcpOPTION_END_BYTE }; size_t xOptionsLength = sizeof( ucDHCPDiscoverOptions ); - pucUDPPayloadBuffer = prvCreatePartDHCPMessage( &xAddress, ( uint8_t ) dhcpREQUEST_OPCODE, ucDHCPDiscoverOptions, &xOptionsLength ); + pucUDPPayloadBuffer = prvCreatePartDHCPMessage( &xAddress, dhcpREQUEST_OPCODE, ucDHCPDiscoverOptions, &xOptionsLength ); FreeRTOS_debug_printf( ( "vDHCPProcess: discover\n" ) ); iptraceSENDING_DHCP_DISCOVER(); diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_DNS.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_DNS.c index e14e7d212..894b7240d 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_DNS.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_DNS.c @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.3 + * FreeRTOS+TCP V2.0.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 @@ -47,17 +47,17 @@ #if( ipconfigUSE_DNS != 0 ) #if( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN ) - #define dnsDNS_PORT 0x3500u - #define dnsONE_QUESTION 0x0100u - #define dnsOUTGOING_FLAGS 0x0001u /* Standard query. */ - #define dnsRX_FLAGS_MASK 0x0f80u /* The bits of interest in the flags field of incoming DNS messages. */ - #define dnsEXPECTED_RX_FLAGS 0x0080u /* Should be a response, without any errors. */ + #define dnsDNS_PORT 0x3500 + #define dnsONE_QUESTION 0x0100 + #define dnsOUTGOING_FLAGS 0x0001 /* Standard query. */ + #define dnsRX_FLAGS_MASK 0x0f80 /* The bits of interest in the flags field of incoming DNS messages. */ + #define dnsEXPECTED_RX_FLAGS 0x0080 /* Should be a response, without any errors. */ #else - #define dnsDNS_PORT 0x0035u - #define dnsONE_QUESTION 0x0001u - #define dnsOUTGOING_FLAGS 0x0100u /* Standard query. */ - #define dnsRX_FLAGS_MASK 0x800fu /* The bits of interest in the flags field of incoming DNS messages. */ - #define dnsEXPECTED_RX_FLAGS 0x8000u /* Should be a response, without any errors. */ + #define dnsDNS_PORT 0x0035 + #define dnsONE_QUESTION 0x0001 + #define dnsOUTGOING_FLAGS 0x0100 /* Standard query. */ + #define dnsRX_FLAGS_MASK 0x800f /* The bits of interest in the flags field of incoming DNS messages. */ + #define dnsEXPECTED_RX_FLAGS 0x8000 /* Should be a response, without any errors. */ #endif /* ipconfigBYTE_ORDER */ @@ -72,29 +72,33 @@ name field is an offset to the string, rather than the string itself. */ #define dnsNAME_IS_OFFSET ( ( uint8_t ) 0xc0 ) /* NBNS flags. */ -#define dnsNBNS_FLAGS_RESPONSE 0x8000u -#define dnsNBNS_FLAGS_OPCODE_MASK 0x7800u -#define dnsNBNS_FLAGS_OPCODE_QUERY 0x0000u -#define dnsNBNS_FLAGS_OPCODE_REGISTRATION 0x2800u +#define dnsNBNS_FLAGS_RESPONSE 0x8000 +#define dnsNBNS_FLAGS_OPCODE_MASK 0x7800 +#define dnsNBNS_FLAGS_OPCODE_QUERY 0x0000 +#define dnsNBNS_FLAGS_OPCODE_REGISTRATION 0x2800 /* Host types. */ -#define dnsTYPE_A_HOST 0x0001u -#define dnsCLASS_IN 0x0001u +#define dnsTYPE_A_HOST 0x01 +#define dnsCLASS_IN 0x01 /* LLMNR constants. */ -#define dnsLLMNR_TTL_VALUE 300000u -#define dnsLLMNR_FLAGS_IS_REPONSE 0x8000u +#define dnsLLMNR_TTL_VALUE 300000 +#define dnsLLMNR_FLAGS_IS_REPONSE 0x8000 /* NBNS constants. */ -#define dnsNBNS_TTL_VALUE 3600u /* 1 hour valid */ -#define dnsNBNS_TYPE_NET_BIOS 0x0020u -#define dnsNBNS_CLASS_IN 0x0001u -#define dnsNBNS_NAME_FLAGS 0x6000u +#define dnsNBNS_TTL_VALUE 3600 /* 1 hour valid */ +#define dnsNBNS_TYPE_NET_BIOS 0x0020 +#define dnsNBNS_CLASS_IN 0x01 +#define dnsNBNS_NAME_FLAGS 0x6000 #define dnsNBNS_ENCODED_NAME_LENGTH 32 /* If the queried NBNS name matches with the device's name, the query will be responded to with these flags: */ -#define dnsNBNS_QUERY_RESPONSE_FLAGS 0x8500u +#define dnsNBNS_QUERY_RESPONSE_FLAGS ( 0x8500 ) + +/* Flag DNS parsing errors in situations where an IPv4 address is the return +type. */ +#define dnsPARSE_ERROR 0UL /* * Create a socket and bind it to the standard DNS port number. Return the @@ -110,12 +114,12 @@ static size_t prvCreateDNSMessage( uint8_t *pucUDPPayloadBuffer, const char *pcH /* * Simple routine that jumps over the NAME field of a resource record. */ -static uint8_t *prvSkipNameField( uint8_t *pucByte ); +static uint8_t *prvSkipNameField( uint8_t *pucByte, size_t xSourceLen ); /* * Process a response packet from a DNS server. */ -static uint32_t prvParseDNSReply( uint8_t *pucUDPPayloadBuffer, TickType_t xIdentifier ); +static uint32_t prvParseDNSReply( uint8_t *pucUDPPayloadBuffer, size_t xBufferLength, TickType_t xIdentifier ); /* * Prepare and send a message to a DNS server. 'xReadTimeOut_ms' will be passed as @@ -131,18 +135,19 @@ static uint32_t prvGetHostByName( const char *pcHostName, TickType_t xIdentifier #endif #if( ipconfigUSE_NBNS == 1 ) - static portINLINE void prvTreatNBNS( uint8_t *pucUDPPayloadBuffer, uint32_t ulIPAddress ); + static portINLINE void prvTreatNBNS( uint8_t *pucUDPPayloadBuffer, size_t xBufferLength, uint32_t ulIPAddress ); #endif /* ipconfigUSE_NBNS */ #if( ipconfigUSE_DNS_CACHE == 1 ) - static uint8_t *prvReadNameField( uint8_t *pucByte, char *pcName, BaseType_t xLen ); - static void prvProcessDNSCache( const char *pcName, uint32_t *pulIP, BaseType_t xLookUp ); + static uint8_t *prvReadNameField( uint8_t *pucByte, size_t xSourceLen, char *pcName, size_t xLen ); + static void prvProcessDNSCache( const char *pcName, uint32_t *pulIP, uint32_t ulTTL, BaseType_t xLookUp ); typedef struct xDNS_CACHE_TABLE_ROW { uint32_t ulIPAddress; /* The IP address of an ARP cache entry. */ - char pcName[ipconfigDNS_CACHE_NAME_LENGTH]; /* The name of the host */ - uint8_t ucAge; /* A value that is periodically decremented but can also be refreshed by active communication. The ARP cache entry is removed if the value reaches zero. */ + char pcName[ ipconfigDNS_CACHE_NAME_LENGTH ]; /* The name of the host */ + uint32_t ulTTL; /* Time-to-Live (in seconds) from the DNS server. */ + uint32_t ulTimeWhenAddedInSeconds; } DNSCacheRow_t; static DNSCacheRow_t xDNSCache[ ipconfigDNS_CACHE_ENTRIES ]; @@ -180,6 +185,18 @@ struct xDNSTail #include "pack_struct_end.h" typedef struct xDNSTail DNSTail_t; +/* DNS answer record header. */ +#include "pack_struct_start.h" +struct xDNSAnswerRecord +{ + uint16_t usType; + uint16_t usClass; + uint32_t ulTTL; + uint16_t usDataLength; +} +#include "pack_struct_end.h" +typedef struct xDNSAnswerRecord DNSAnswerRecord_t; + #if( ipconfigUSE_LLMNR == 1 ) #include "pack_struct_start.h" @@ -239,7 +256,7 @@ typedef struct xDNSTail DNSTail_t; uint32_t FreeRTOS_dnslookup( const char *pcHostName ) { uint32_t ulIPAddress = 0UL; - prvProcessDNSCache( pcHostName, &ulIPAddress, pdTRUE ); + prvProcessDNSCache( pcHostName, &ulIPAddress, 0, pdTRUE ); return ulIPAddress; } #endif /* ipconfigUSE_DNS_CACHE == 1 */ @@ -396,64 +413,70 @@ uint32_t FreeRTOS_gethostbyname_a( const char *pcHostName, FOnDNSEvent pCallback #endif { uint32_t ulIPAddress = 0UL; -static uint16_t usIdentifier = 0u; -TickType_t xReadTimeOut_ms = 1200U; -/* Generate a unique identifier for this query. Keep it in a local variable - as gethostbyname() may be called from different threads */ -TickType_t xIdentifier = ( TickType_t )usIdentifier++; - - /* If the supplied hostname is IP address, convert it to uint32_t - and return. */ - #if( ipconfigINCLUDE_FULL_INET_ADDR == 1 ) - { - ulIPAddress = FreeRTOS_inet_addr( pcHostName ); - } - #endif /* ipconfigINCLUDE_FULL_INET_ADDR == 1 */ - - /* If a DNS cache is used then check the cache before issuing another DNS - request. */ - #if( ipconfigUSE_DNS_CACHE == 1 ) - { - if( ulIPAddress == 0UL ) - { - ulIPAddress = FreeRTOS_dnslookup( pcHostName ); - if( ulIPAddress != 0 ) - { - FreeRTOS_debug_printf( ( "FreeRTOS_gethostbyname: found '%s' in cache: %lxip\n", pcHostName, ulIPAddress ) ); - } - else - { - /* prvGetHostByName will be called to start a DNS lookup */ - } - } - } - #endif /* ipconfigUSE_DNS_CACHE == 1 */ - - #if( ipconfigDNS_USE_CALLBACKS != 0 ) - { - if( pCallback != NULL ) - { - if( ulIPAddress == 0UL ) - { - /* The user has provided a callback function, so do not block on recvfrom() */ - xReadTimeOut_ms = 0; - vDNSSetCallBack( pcHostName, pvSearchID, pCallback, xTimeout, ( TickType_t ) xIdentifier ); - } - else - { - /* The IP address is known, do the call-back now. */ - pCallback( pcHostName, pvSearchID, ulIPAddress ); - } - } - } - #endif - - if( ulIPAddress == 0UL) - { - ulIPAddress = prvGetHostByName( pcHostName, xIdentifier, xReadTimeOut_ms ); - } - - return ulIPAddress; +TickType_t xReadTimeOut_ms = ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME; +TickType_t xIdentifier = 0; + + /* If the supplied hostname is IP address, convert it to uint32_t + and return. */ + #if( ipconfigINCLUDE_FULL_INET_ADDR == 1 ) + { + ulIPAddress = FreeRTOS_inet_addr( pcHostName ); + } + #endif /* ipconfigINCLUDE_FULL_INET_ADDR == 1 */ + + /* If a DNS cache is used then check the cache before issuing another DNS + request. */ + #if( ipconfigUSE_DNS_CACHE == 1 ) + { + if( ulIPAddress == 0UL ) + { + ulIPAddress = FreeRTOS_dnslookup( pcHostName ); + if( ulIPAddress != 0 ) + { + FreeRTOS_debug_printf( ( "FreeRTOS_gethostbyname: found '%s' in cache: %lxip\n", pcHostName, ulIPAddress ) ); + } + else + { + /* prvGetHostByName will be called to start a DNS lookup */ + } + } + } + #endif /* ipconfigUSE_DNS_CACHE == 1 */ + + /* Generate a unique identifier. */ + if( 0 == ulIPAddress ) + { + xIdentifier = ( TickType_t )ipconfigRAND32( ); + } + + #if( ipconfigDNS_USE_CALLBACKS != 0 ) + { + if( pCallback != NULL ) + { + if( ulIPAddress == 0UL ) + { + /* The user has provided a callback function, so do not block on recvfrom() */ + if( 0 != xIdentifier ) + { + xReadTimeOut_ms = 0; + vDNSSetCallBack( pcHostName, pvSearchID, pCallback, xTimeout, ( TickType_t )xIdentifier ); + } + } + else + { + /* The IP address is known, do the call-back now. */ + pCallback( pcHostName, pvSearchID, ulIPAddress ); + } + } + } + #endif + + if( ulIPAddress == 0UL && 0 != xIdentifier ) + { + ulIPAddress = prvGetHostByName( pcHostName, xIdentifier, xReadTimeOut_ms ); + } + + return ulIPAddress; } /*-----------------------------------------------------------*/ @@ -467,7 +490,7 @@ uint32_t ulAddressLength = sizeof( struct freertos_sockaddr ); BaseType_t xAttempt; int32_t lBytes; size_t xPayloadLength, xExpectedPayloadLength; -TickType_t xWriteTimeOut_ms = 100U; +TickType_t xWriteTimeOut_ms = ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME; #if( ipconfigUSE_LLMNR == 1 ) BaseType_t bHasDot = pdFALSE; @@ -544,7 +567,7 @@ TickType_t xWriteTimeOut_ms = 100U; if( lBytes > 0 ) { /* The reply was received. Process it. */ - ulIPAddress = prvParseDNSReply( pucUDPPayloadBuffer, xIdentifier ); + ulIPAddress = prvParseDNSReply( pucUDPPayloadBuffer, lBytes, xIdentifier ); /* Finished with the buffer. The zero copy interface is being used, so the buffer must be freed by the @@ -649,33 +672,74 @@ static const DNSMessage_t xDefaultPartDNSHeader = #if( ipconfigUSE_DNS_CACHE == 1 ) - static uint8_t *prvReadNameField( uint8_t *pucByte, char *pcName, BaseType_t xLen ) + static uint8_t *prvReadNameField( uint8_t *pucByte, size_t xSourceLen, char *pcName, size_t xDestLen ) { - BaseType_t xNameLen = 0; + size_t xNameLen = 0; + BaseType_t xCount; + + if( 0 == xSourceLen ) + { + return NULL; + } + /* Determine if the name is the fully coded name, or an offset to the name elsewhere in the message. */ if( ( *pucByte & dnsNAME_IS_OFFSET ) == dnsNAME_IS_OFFSET ) { /* Jump over the two byte offset. */ - pucByte += sizeof( uint16_t ); - + if( xSourceLen > sizeof( uint16_t ) ) + { + pucByte += sizeof( uint16_t ); + } + else + { + pucByte = NULL; + } } else { - /* pucByte points to the full name. Walk over the string. */ - while( *pucByte != 0x00 ) + /* pucByte points to the full name. Walk over the string. */ + while( NULL != pucByte && *pucByte != 0x00 && xSourceLen > 1 ) { - BaseType_t xCount; - if( xNameLen && xNameLen < xLen - 1 ) - pcName[xNameLen++] = '.'; - for( xCount = *(pucByte++); xCount--; pucByte++ ) + /* If this is not the first time through the loop, then add a + separator in the output. */ + if( xNameLen > 0 && xNameLen < xDestLen - 1 ) + { + pcName[ xNameLen++ ] = '.'; + } + + /* Process the first/next sub-string. */ + for( xCount = *(pucByte++), xSourceLen--; + xCount-- && xSourceLen > 1; + pucByte++, xSourceLen-- ) { - if( xNameLen < xLen - 1 ) - pcName[xNameLen++] = *( ( char * ) pucByte ); + if( xNameLen < xDestLen - 1 ) + { + pcName[ xNameLen++ ] = *( ( char * )pucByte ); + } + else + { + /* DNS name is too big for the provided buffer. */ + pucByte = NULL; + break; + } } } - pucByte++; + /* Confirm that a fully formed name was found. */ + if( NULL != pucByte ) + { + if( 0x00 == *pucByte ) + { + pucByte++; + xSourceLen--; + pcName[ xNameLen++ ] = '\0'; + } + else + { + pucByte = NULL; + } + } } return pucByte; @@ -683,27 +747,60 @@ static const DNSMessage_t xDefaultPartDNSHeader = #endif /* ipconfigUSE_DNS_CACHE == 1 */ /*-----------------------------------------------------------*/ -static uint8_t *prvSkipNameField( uint8_t *pucByte ) +static uint8_t *prvSkipNameField( uint8_t *pucByte, size_t xSourceLen ) { - /* Determine if the name is the fully coded name, or an offset to the name + size_t xChunkLength; + + if( 0 == xSourceLen ) + { + return NULL; + } + + /* Determine if the name is the fully coded name, or an offset to the name elsewhere in the message. */ if( ( *pucByte & dnsNAME_IS_OFFSET ) == dnsNAME_IS_OFFSET ) { /* Jump over the two byte offset. */ - pucByte += sizeof( uint16_t ); - + if( xSourceLen > sizeof( uint16_t ) ) + { + pucByte += sizeof( uint16_t ); + } + else + { + pucByte = NULL; + } } else { - /* pucByte points to the full name. Walk over the string. */ - while( *pucByte != 0x00 ) + /* pucByte points to the full name. Walk over the string. */ + while( *pucByte != 0x00 && xSourceLen > 1 ) { - /* The number of bytes to jump for each name section is stored in the byte - before the name section. */ - pucByte += ( *pucByte + 1 ); + xChunkLength = *pucByte + 1; + + if( xSourceLen > xChunkLength ) + { + xSourceLen -= xChunkLength; + pucByte += xChunkLength; + } + else + { + pucByte = NULL; + break; + } } - pucByte++; + /* Confirm that a fully formed name was found. */ + if( NULL != pucByte ) + { + if( 0x00 == *pucByte ) + { + pucByte++; + } + else + { + pucByte = NULL; + } + } } return pucByte; @@ -712,10 +809,25 @@ static uint8_t *prvSkipNameField( uint8_t *pucByte ) uint32_t ulDNSHandlePacket( NetworkBufferDescriptor_t *pxNetworkBuffer ) { -uint8_t *pucUDPPayloadBuffer = pxNetworkBuffer->pucEthernetBuffer + sizeof( UDPPacket_t ); -DNSMessage_t *pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer; +uint8_t *pucUDPPayloadBuffer; +size_t xPlayloadBufferLength; +DNSMessage_t *pxDNSMessageHeader; - prvParseDNSReply( pucUDPPayloadBuffer, ( uint32_t ) pxDNSMessageHeader->usIdentifier ); + xPlayloadBufferLength = pxNetworkBuffer->xDataLength - sizeof( UDPPacket_t ); + if ( xPlayloadBufferLength < sizeof( DNSMessage_t ) ) + { + return pdFAIL; + } + + pucUDPPayloadBuffer = pxNetworkBuffer->pucEthernetBuffer + sizeof( UDPPacket_t ); + pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer; + + if( pxNetworkBuffer->xDataLength > sizeof( UDPPacket_t ) ) + { + prvParseDNSReply( pucUDPPayloadBuffer, + xPlayloadBufferLength, + ( uint32_t )pxDNSMessageHeader->usIdentifier ); + } /* The packet was not consumed. */ return pdFAIL; @@ -727,9 +839,14 @@ DNSMessage_t *pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer; uint32_t ulNBNSHandlePacket (NetworkBufferDescriptor_t *pxNetworkBuffer ) { UDPPacket_t *pxUDPPacket = ( UDPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer; - uint8_t *pucUDPPayloadBuffer = pxNetworkBuffer->pucEthernetBuffer + sizeof( *pxUDPPacket ); + uint8_t *pucUDPPayloadBuffer = pxNetworkBuffer->pucEthernetBuffer + sizeof( UDPPacket_t ); - prvTreatNBNS( pucUDPPayloadBuffer, pxUDPPacket->xIPHeader.ulSourceIPAddress ); + if( pxNetworkBuffer->xDataLength > sizeof( UDPPacket_t) ) + { + prvTreatNBNS( pucUDPPayloadBuffer, + pxNetworkBuffer->xDataLength - sizeof( UDPPacket_t ), + pxUDPPacket->xIPHeader.ulSourceIPAddress ); + } /* The packet was not consumed. */ return pdFAIL; @@ -738,28 +855,42 @@ DNSMessage_t *pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer; #endif /* ipconfigUSE_NBNS */ /*-----------------------------------------------------------*/ -static uint32_t prvParseDNSReply( uint8_t *pucUDPPayloadBuffer, TickType_t xIdentifier ) +static uint32_t prvParseDNSReply( uint8_t *pucUDPPayloadBuffer, size_t xBufferLength, TickType_t xIdentifier ) { DNSMessage_t *pxDNSMessageHeader; +DNSAnswerRecord_t *pxDNSAnswerRecord; uint32_t ulIPAddress = 0UL; #if( ipconfigUSE_LLMNR == 1 ) char *pcRequestedName = NULL; #endif uint8_t *pucByte; +size_t xSourceBytesRemaining; uint16_t x, usDataLength, usQuestions; #if( ipconfigUSE_LLMNR == 1 ) uint16_t usType = 0, usClass = 0; #endif #if( ipconfigUSE_DNS_CACHE == 1 ) - char pcName[128] = ""; /*_RB_ What is the significance of 128? Probably too big to go on the stack for a small MCU but don't know how else it could be made re-entrant. Might be necessary. */ + char pcName[ ipconfigDNS_CACHE_NAME_LENGTH ] = ""; #endif + /* Ensure that the buffer is of at least minimal DNS message length. */ + if( xBufferLength < sizeof( DNSMessage_t ) ) + { + return dnsPARSE_ERROR; + } + else + { + xSourceBytesRemaining = xBufferLength; + } + + /* Parse the DNS message header. */ pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer; if( pxDNSMessageHeader->usIdentifier == ( uint16_t ) xIdentifier ) { /* Start at the first byte after the header. */ pucByte = pucUDPPayloadBuffer + sizeof( DNSMessage_t ); + xSourceBytesRemaining -= sizeof( DNSMessage_t ); /* Skip any question records. */ usQuestions = FreeRTOS_ntohs( pxDNSMessageHeader->usQuestions ); @@ -777,56 +908,100 @@ uint16_t x, usDataLength, usQuestions; #if( ipconfigUSE_DNS_CACHE == 1 ) if( x == 0 ) { - pucByte = prvReadNameField( pucByte, pcName, sizeof( pcName ) ); + pucByte = prvReadNameField( pucByte, + xSourceBytesRemaining, + pcName, + sizeof( pcName ) ); + + /* Check for a malformed response. */ + if( NULL == pucByte ) + { + return dnsPARSE_ERROR; + } + else + { + xSourceBytesRemaining = ( pucUDPPayloadBuffer + xBufferLength ) - pucByte; + } } else #endif /* ipconfigUSE_DNS_CACHE */ { /* Skip the variable length pcName field. */ - pucByte = prvSkipNameField( pucByte ); - } - - #if( ipconfigUSE_LLMNR == 1 ) - { - /* usChar2u16 returns value in host endianness. */ - usType = usChar2u16( pucByte ); - usClass = usChar2u16( pucByte + 2 ); - } - #endif /* ipconfigUSE_LLMNR */ - - /* Skip the type and class fields. */ - pucByte += sizeof( uint32_t ); + pucByte = prvSkipNameField( pucByte, + xSourceBytesRemaining ); + + /* Check for a malformed response. */ + if( NULL == pucByte ) + { + return dnsPARSE_ERROR; + } + else + { + xSourceBytesRemaining = pucUDPPayloadBuffer + xBufferLength - pucByte; + } + } + + /* Check the remaining buffer size. */ + if( xSourceBytesRemaining >= sizeof( uint32_t ) ) + { + #if( ipconfigUSE_LLMNR == 1 ) + { + /* usChar2u16 returns value in host endianness */ + usType = usChar2u16( pucByte ); + usClass = usChar2u16( pucByte + 2 ); + } + #endif /* ipconfigUSE_LLMNR */ + + /* Skip the type and class fields. */ + pucByte += sizeof( uint32_t ); + xSourceBytesRemaining -= sizeof( uint32_t ); + } + else + { + /* Malformed response. */ + return dnsPARSE_ERROR; + } } - /* Search through the answers records. */ + /* Search through the answer records. */ pxDNSMessageHeader->usAnswers = FreeRTOS_ntohs( pxDNSMessageHeader->usAnswers ); if( ( pxDNSMessageHeader->usFlags & dnsRX_FLAGS_MASK ) == dnsEXPECTED_RX_FLAGS ) { for( x = 0; x < pxDNSMessageHeader->usAnswers; x++ ) { - pucByte = prvSkipNameField( pucByte ); - - /* Is the type field that of an A record? */ - if( usChar2u16( pucByte ) == dnsTYPE_A_HOST ) + pucByte = prvSkipNameField( pucByte, + xSourceBytesRemaining ); + + /* Check for a malformed response. */ + if( NULL == pucByte ) + { + return dnsPARSE_ERROR; + } + else + { + xSourceBytesRemaining = pucUDPPayloadBuffer + xBufferLength - pucByte; + } + + /* Is there enough data for an IPv4 A record answer and, if so, + is this an A record? */ + if( xSourceBytesRemaining >= sizeof( DNSAnswerRecord_t ) + sizeof( uint32_t ) && + usChar2u16( pucByte ) == dnsTYPE_A_HOST ) { - /* This is the required record. Skip the type, class, and - time to live fields, plus the first byte of the data - length. */ - pucByte += ( sizeof( uint32_t ) + sizeof( uint32_t ) + sizeof( uint8_t ) ); + /* This is the required record type and is of sufficient size. */ + pxDNSAnswerRecord = ( DNSAnswerRecord_t * )pucByte; - /* Sanity check the data length. */ - if( ( size_t ) *pucByte == sizeof( uint32_t ) ) + /* Sanity check the data length of an IPv4 answer. */ + if( FreeRTOS_ntohs( pxDNSAnswerRecord->usDataLength ) == sizeof( uint32_t ) ) { - /* Skip the second byte of the length. */ - pucByte++; - /* Copy the IP address out of the record. */ - memcpy( ( void * ) &ulIPAddress, ( void * ) pucByte, sizeof( uint32_t ) ); + memcpy( &ulIPAddress, + pucByte + sizeof( DNSAnswerRecord_t ), + sizeof( uint32_t ) ); #if( ipconfigUSE_DNS_CACHE == 1 ) { - prvProcessDNSCache( pcName, &ulIPAddress, pdFALSE ); + prvProcessDNSCache( pcName, &ulIPAddress, pxDNSAnswerRecord->ulTTL, pdFALSE ); } #endif /* ipconfigUSE_DNS_CACHE */ #if( ipconfigDNS_USE_CALLBACKS != 0 ) @@ -837,24 +1012,37 @@ uint16_t x, usDataLength, usQuestions; #endif /* ipconfigDNS_USE_CALLBACKS != 0 */ } + pucByte += sizeof( DNSAnswerRecord_t ) + sizeof( uint32_t ); + xSourceBytesRemaining -= ( sizeof( DNSAnswerRecord_t ) + sizeof( uint32_t ) ); break; } - else + else if( xSourceBytesRemaining >= sizeof( DNSAnswerRecord_t ) ) { - /* Skip the type, class and time to live fields. */ - pucByte += ( sizeof( uint32_t ) + sizeof( uint32_t ) ); - - /* Determine the length of the data in the field. */ - memcpy( ( void * ) &usDataLength, ( void * ) pucByte, sizeof( uint16_t ) ); - usDataLength = FreeRTOS_ntohs( usDataLength ); - - /* Jump over the data length bytes, and the data itself. */ - pucByte += usDataLength + sizeof( uint16_t ); + /* It's not an A record, so skip it. Get the header location + and then jump over the header. */ + pxDNSAnswerRecord = ( DNSAnswerRecord_t * )pucByte; + pucByte += sizeof( DNSAnswerRecord_t ); + xSourceBytesRemaining -= sizeof( DNSAnswerRecord_t ); + + /* Determine the length of the answer data from the header. */ + usDataLength = FreeRTOS_ntohs( pxDNSAnswerRecord->usDataLength ); + + /* Jump over the answer. */ + if( xSourceBytesRemaining >= usDataLength ) + { + pucByte += usDataLength; + xSourceBytesRemaining -= usDataLength; + } + else + { + /* Malformed response. */ + return dnsPARSE_ERROR; + } } } } #if( ipconfigUSE_LLMNR == 1 ) - else if( ( usQuestions != ( uint16_t )0u ) && ( usType == ( uint16_t )dnsTYPE_A_HOST ) && ( usClass == ( uint16_t )dnsCLASS_IN ) ) + else if( usQuestions && ( usType == dnsTYPE_A_HOST ) && ( usClass == dnsCLASS_IN ) ) { /* If this is not a reply to our DNS request, it might an LLMNR request. */ @@ -867,7 +1055,7 @@ uint16_t x, usDataLength, usQuestions; if( ( xBufferAllocFixedSize == pdFALSE ) && ( pxNetworkBuffer != NULL ) ) { - BaseType_t xDataLength = pxNetworkBuffer->xDataLength + sizeof( UDPHeader_t ) + + BaseType_t xDataLength = xBufferLength + sizeof( UDPHeader_t ) + sizeof( EthernetHeader_t ) + sizeof( IPHeader_t ); /* The field xDataLength was set to the length of the UDP payload. @@ -900,7 +1088,7 @@ uint16_t x, usDataLength, usQuestions; { pxAnswer = (LLMNRAnswer_t *)pucByte; - /* Leave 'usIdentifier' and 'usQuestions' untouched. */ + /* We leave 'usIdentifier' and 'usQuestions' untouched */ vSetField16( pxDNSMessageHeader, DNSMessage_t, usFlags, dnsLLMNR_FLAGS_IS_REPONSE ); /* Set the response flag */ vSetField16( pxDNSMessageHeader, DNSMessage_t, usAnswers, 1 ); /* Provide a single answer */ vSetField16( pxDNSMessageHeader, DNSMessage_t, usAuthorityRRs, 0 ); /* No authority */ @@ -935,13 +1123,20 @@ uint16_t x, usDataLength, usQuestions; #if( ipconfigUSE_NBNS == 1 ) - static void prvTreatNBNS( uint8_t *pucUDPPayloadBuffer, uint32_t ulIPAddress ) + static void prvTreatNBNS( uint8_t *pucUDPPayloadBuffer, size_t xBufferLength, uint32_t ulIPAddress ) { uint16_t usFlags, usType, usClass; uint8_t *pucSource, *pucTarget; uint8_t ucByte; uint8_t ucNBNSName[ 17 ]; + /* Check for minimum buffer size. */ + if( xBufferLength < sizeof( NBNSRequest_t ) ) + { + return; + } + + /* Read the request flags in host endianness. */ usFlags = usChar2u16( pucUDPPayloadBuffer + offsetof( NBNSRequest_t, usFlags ) ); if( ( usFlags & dnsNBNS_FLAGS_OPCODE_MASK ) == dnsNBNS_FLAGS_OPCODE_QUERY ) @@ -986,7 +1181,7 @@ uint16_t x, usDataLength, usQuestions; { /* If this is a response from another device, add the name to the DNS cache */ - prvProcessDNSCache( ( char * ) ucNBNSName, &ulIPAddress, pdFALSE ); + prvProcessDNSCache( ( char * ) ucNBNSName, &ulIPAddress, 0, pdFALSE ); } } #else @@ -1012,7 +1207,6 @@ uint16_t x, usDataLength, usQuestions; { NetworkBufferDescriptor_t *pxNewBuffer; BaseType_t xDataLength = pxNetworkBuffer->xDataLength + sizeof( UDPHeader_t ) + - sizeof( EthernetHeader_t ) + sizeof( IPHeader_t ); /* The field xDataLength was set to the length of the UDP payload. @@ -1127,7 +1321,7 @@ TickType_t xTimeoutTime = pdMS_TO_TICKS( 200 ); pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum ); /* calculate the UDP checksum for outgoing package */ - usGenerateProtocolChecksum( ( uint8_t* ) pxUDPPacket, pdTRUE ); + usGenerateProtocolChecksum( ( uint8_t* ) pxUDPPacket, lNetLength, pdTRUE ); } #endif @@ -1143,10 +1337,12 @@ TickType_t xTimeoutTime = pdMS_TO_TICKS( 200 ); #if( ipconfigUSE_DNS_CACHE == 1 ) - static void prvProcessDNSCache( const char *pcName, uint32_t *pulIP, BaseType_t xLookUp ) + static void prvProcessDNSCache( const char *pcName, uint32_t *pulIP, uint32_t ulTTL, BaseType_t xLookUp ) { BaseType_t x; BaseType_t xFound = pdFALSE; + uint32_t ulCurrentTimeSeconds = + xTaskGetTickCount( ) / portTICK_PERIOD_MS / 1000; static BaseType_t xFreeEntry = 0; /* For each entry in the DNS cache table. */ @@ -1157,16 +1353,29 @@ TickType_t xTimeoutTime = pdMS_TO_TICKS( 200 ); break; } - if( strncmp( xDNSCache[ x ].pcName, pcName, sizeof( xDNSCache[ x ].pcName ) ) == 0 ) + if( 0 == strcmp( xDNSCache[ x ].pcName, pcName ) ) { /* Is this function called for a lookup or to add/update an IP address? */ if( xLookUp != pdFALSE ) { - *pulIP = xDNSCache[ x ].ulIPAddress; + /* Confirm that the record is still fresh. */ + if( ulCurrentTimeSeconds < + xDNSCache[ x ].ulTimeWhenAddedInSeconds + + FreeRTOS_ntohl( xDNSCache[ x ].ulTTL ) ) + { + *pulIP = xDNSCache[ x ].ulIPAddress; + } + else + { + /* Age out the old cached record. */ + xDNSCache[ x ].pcName[ 0 ] = 0; + } } else { xDNSCache[ x ].ulIPAddress = *pulIP; + xDNSCache[ x ].ulTTL = ulTTL; + xDNSCache[ x ].ulTimeWhenAddedInSeconds = ulCurrentTimeSeconds; } xFound = pdTRUE; @@ -1182,15 +1391,21 @@ TickType_t xTimeoutTime = pdMS_TO_TICKS( 200 ); } else { - /* Called to add or update an item */ - strncpy( xDNSCache[ xFreeEntry ].pcName, pcName, sizeof( xDNSCache[ xFreeEntry ].pcName ) ); - xDNSCache[ xFreeEntry ].ulIPAddress = *pulIP; - - xFreeEntry++; - if( xFreeEntry == ipconfigDNS_CACHE_ENTRIES ) - { - xFreeEntry = 0; - } + /* Add or update the item. */ + if( strlen( pcName ) < ipconfigDNS_CACHE_NAME_LENGTH ) + { + strcpy( xDNSCache[ xFreeEntry ].pcName, pcName ); + + xDNSCache[ xFreeEntry ].ulIPAddress = *pulIP; + xDNSCache[ xFreeEntry ].ulTTL = ulTTL; + xDNSCache[ xFreeEntry ].ulTimeWhenAddedInSeconds = ulCurrentTimeSeconds; + + xFreeEntry++; + if( xFreeEntry == ipconfigDNS_CACHE_ENTRIES ) + { + xFreeEntry = 0; + } + } } } @@ -1204,4 +1419,9 @@ TickType_t xTimeoutTime = pdMS_TO_TICKS( 200 ); #endif /* ipconfigUSE_DNS != 0 */ +/*-----------------------------------------------------------*/ +/* Provide access to private members for testing. */ +#ifdef AMAZON_FREERTOS_ENABLE_UNIT_TESTS + #include "aws_freertos_tcp_test_access_dns_define.h" +#endif diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_IP.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_IP.c index 7f311ade8..fdb8fd116 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_IP.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_IP.c @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.3 + * FreeRTOS+TCP V2.0.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 @@ -65,9 +65,7 @@ a constant. */ /* Time delay between repeated attempts to initialise the network hardware. */ -#ifndef ipINITIALISATION_RETRY_DELAY - #define ipINITIALISATION_RETRY_DELAY ( pdMS_TO_TICKS( 3000 ) ) -#endif +#define ipINITIALISATION_RETRY_DELAY ( pdMS_TO_TICKS( 3000 ) ) /* Defines how often the ARP timer callback function is executed. The time is shorted in the Windows simulator as simulated time is not real time. */ @@ -186,7 +184,7 @@ static void prvProcessEthernetPacket( NetworkBufferDescriptor_t * const pxNetwor /* * Process incoming IP packets. */ -static eFrameProcessingResult_t prvProcessIPPacket( const IPPacket_t * const pxIPPacket, NetworkBufferDescriptor_t * const pxNetworkBuffer ); +static eFrameProcessingResult_t prvProcessIPPacket( IPPacket_t * const pxIPPacket, NetworkBufferDescriptor_t * const pxNetworkBuffer ); #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) /* @@ -356,11 +354,12 @@ struct freertos_sockaddr xAddress; /* Calculate the acceptable maximum sleep time. */ xNextIPSleep = prvCalculateSleepTime(); - /* Wait until there is something to do. The event is initialised to "no - event" in case the following call exits due to a time out rather than a - message being received. */ - xReceivedEvent.eEventType = eNoEvent; - xQueueReceive( xNetworkEventQueue, ( void * ) &xReceivedEvent, xNextIPSleep ); + /* Wait until there is something to do. If the following call exits + * due to a time out rather than a message being received, set a + * 'NoEvent' value. */ + if ( xQueueReceive( xNetworkEventQueue, ( void * ) &xReceivedEvent, xNextIPSleep ) == pdFALSE ) { + xReceivedEvent.eEventType = eNoEvent; + } #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 ) { @@ -655,14 +654,8 @@ static void prvCheckNetworkTimers( void ) #if( ipconfigUSE_TCP == 1 ) { BaseType_t xWillSleep; - /* xStart keeps a copy of the last time this function was active, - and during every call it will be updated with xTaskGetTickCount() - '0' means: not yet initialised (although later '0' might be returned - by xTaskGetTickCount(), which is no problem). */ - static TickType_t xStart = ( TickType_t ) 0; - TickType_t xTimeNow, xNextTime; + TickType_t xNextTime; BaseType_t xCheckTCPSockets; - extern uint32_t ulNextInitialSequenceNumber; if( uxQueueMessagesWaiting( xNetworkEventQueue ) == 0u ) { @@ -673,19 +666,6 @@ static void prvCheckNetworkTimers( void ) xWillSleep = pdFALSE; } - xTimeNow = xTaskGetTickCount(); - - if( xStart != ( TickType_t ) 0 ) - { - /* It is advised to increment the Initial Sequence Number every 4 - microseconds which makes 250 times per ms. This will make it harder - for a third party to 'guess' our sequence number and 'take over' - a TCP connection */ - ulNextInitialSequenceNumber += ipINITIAL_SEQUENCE_NUMBER_FACTOR * ( ( xTimeNow - xStart ) * portTICK_PERIOD_MS ); - } - - xStart = xTimeNow; - /* Sockets need to be checked if the TCP timer has expired. */ xCheckTCPSockets = prvIPTimerCheck( &xTCPTimer ); @@ -823,6 +803,10 @@ void *pvReturn; if( pxNetworkBuffer != NULL ) { + /* Set the actual packet size in case a bigger buffer was returned. */ + pxNetworkBuffer->xDataLength = + sizeof( UDPPacket_t ) + xRequestedSizeBytes; + /* Leave space for the UPD header. */ pvReturn = ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] ); } @@ -847,6 +831,11 @@ NetworkBufferDescriptor_t * pxNewBuffer; if( pxNewBuffer != NULL ) { + /* Set the actual packet size in case a bigger buffer than requested + was returned. */ + pxNewBuffer->xDataLength = xNewLength; + + /* Copy the original packet information. */ pxNewBuffer->ulIPAddress = pxNetworkBuffer->ulIPAddress; pxNewBuffer->usPort = pxNetworkBuffer->usPort; pxNewBuffer->usBoundPort = pxNetworkBuffer->usBoundPort; @@ -997,10 +986,7 @@ BaseType_t xReturn = pdFALSE; /* Added to prevent ARP flood to gateway. Ensure the gateway is on the same subnet as the IP address. */ - if( xNetworkAddressing.ulGatewayAddress != 0ul ) - { - configASSERT( ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) == ( xNetworkAddressing.ulGatewayAddress & xNetworkAddressing.ulNetMask ) ); - } + configASSERT( ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) == ( xNetworkAddressing.ulGatewayAddress & xNetworkAddressing.ulNetMask ) ); } #endif /* ipconfigUSE_DHCP == 1 */ @@ -1009,10 +995,13 @@ BaseType_t xReturn = pdFALSE; memcpy( ( void * ) ipLOCAL_MAC_ADDRESS, ( void * ) ucMACAddress, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES ); /* Prepare the sockets interface. */ - vNetworkSocketsInit(); - - /* Create the task that processes Ethernet and stack events. */ - xReturn = xTaskCreate( prvIPTask, "IP-task", ( uint16_t ) ipconfigIP_TASK_STACK_SIZE_WORDS, NULL, ( UBaseType_t ) ipconfigIP_TASK_PRIORITY, &xIPTaskHandle ); + xReturn = vNetworkSocketsInit(); + + if( pdTRUE == xReturn ) + { + /* Create the task that processes Ethernet and stack events. */ + xReturn = xTaskCreate( prvIPTask, "IP-task", ( uint16_t )ipconfigIP_TASK_STACK_SIZE_WORDS, NULL, ( UBaseType_t )ipconfigIP_TASK_PRIORITY, &xIPTaskHandle ); + } } else { @@ -1356,35 +1345,52 @@ void vIPNetworkUpCalls( void ) static void prvProcessEthernetPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer ) { EthernetHeader_t *pxEthernetHeader; -volatile eFrameProcessingResult_t eReturned; /* Volatile to prevent complier warnings when ipCONSIDER_FRAME_FOR_PROCESSING just sets it to eProcessBuffer. */ +eFrameProcessingResult_t eReturned = eReleaseBuffer; configASSERT( pxNetworkBuffer ); /* Interpret the Ethernet frame. */ - eReturned = ipCONSIDER_FRAME_FOR_PROCESSING( pxNetworkBuffer->pucEthernetBuffer ); - pxEthernetHeader = ( EthernetHeader_t * ) ( pxNetworkBuffer->pucEthernetBuffer ); - - if( eReturned == eProcessBuffer ) - { - /* Interpret the received Ethernet packet. */ - switch( pxEthernetHeader->usFrameType ) - { - case ipARP_FRAME_TYPE : - /* The Ethernet frame contains an ARP packet. */ - eReturned = eARPProcessPacket( ( ARPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer ); - break; - - case ipIPv4_FRAME_TYPE : - /* The Ethernet frame contains an IP packet. */ - eReturned = prvProcessIPPacket( ( IPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer ); - break; - - default : - /* No other packet types are handled. Nothing to do. */ - eReturned = eReleaseBuffer; - break; - } - } + if( pxNetworkBuffer->xDataLength >= sizeof( EthernetHeader_t ) ) + { + eReturned = ipCONSIDER_FRAME_FOR_PROCESSING( pxNetworkBuffer->pucEthernetBuffer ); + pxEthernetHeader = ( EthernetHeader_t * )( pxNetworkBuffer->pucEthernetBuffer ); + + if( eReturned == eProcessBuffer ) + { + /* Interpret the received Ethernet packet. */ + switch( pxEthernetHeader->usFrameType ) + { + case ipARP_FRAME_TYPE: + /* The Ethernet frame contains an ARP packet. */ + if( pxNetworkBuffer->xDataLength >= sizeof( ARPPacket_t ) ) + { + eReturned = eARPProcessPacket( ( ARPPacket_t * )pxNetworkBuffer->pucEthernetBuffer ); + } + else + { + eReturned = eReleaseBuffer; + } + break; + + case ipIPv4_FRAME_TYPE: + /* The Ethernet frame contains an IP packet. */ + if( pxNetworkBuffer->xDataLength >= sizeof( IPPacket_t ) ) + { + eReturned = prvProcessIPPacket( ( IPPacket_t * )pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer ); + } + else + { + eReturned = eReleaseBuffer; + } + break; + + default: + /* No other packet types are handled. Nothing to do. */ + eReturned = eReleaseBuffer; + break; + } + } + } /* Perform any actions that resulted from processing the Ethernet frame. */ switch( eReturned ) @@ -1433,9 +1439,9 @@ eFrameProcessingResult_t eReturn = eProcessBuffer; This method may decrease the usage of sparse network buffers. */ uint32_t ulDestinationIPAddress = pxIPHeader->ulDestinationIPAddress; - /* Ensure that the incoming packet is not fragmented (fragmentation - was only supported for outgoing packets, and is not currently - not supported at all). */ + /* Ensure that the incoming packet is not fragmented (only outgoing + packets can be fragmented) as these are the only handled IP frames + currently. */ if( ( pxIPHeader->usFragmentOffset & ipFRAGMENT_OFFSET_BIT_MASK ) != 0U ) { /* Can not handle, fragmented packet. */ @@ -1481,7 +1487,7 @@ eFrameProcessingResult_t eReturn = eProcessBuffer; eReturn = eReleaseBuffer; } /* Is the upper-layer checksum (TCP/UDP/ICMP) correct? */ - else if( usGenerateProtocolChecksum( ( uint8_t * )( pxNetworkBuffer->pucEthernetBuffer ), pdFALSE ) != ipCORRECT_CRC ) + else if( usGenerateProtocolChecksum( ( uint8_t * )( pxNetworkBuffer->pucEthernetBuffer ), pxNetworkBuffer->xDataLength, pdFALSE ) != ipCORRECT_CRC ) { /* Protocol checksum not accepted. */ eReturn = eReleaseBuffer; @@ -1500,13 +1506,22 @@ eFrameProcessingResult_t eReturn = eProcessBuffer; } /*-----------------------------------------------------------*/ -static eFrameProcessingResult_t prvProcessIPPacket( const IPPacket_t * const pxIPPacket, NetworkBufferDescriptor_t * const pxNetworkBuffer ) +static eFrameProcessingResult_t prvProcessIPPacket( IPPacket_t * const pxIPPacket, NetworkBufferDescriptor_t * const pxNetworkBuffer ) { eFrameProcessingResult_t eReturn; -const IPHeader_t * pxIPHeader = &( pxIPPacket->xIPHeader ); +IPHeader_t * pxIPHeader = &( pxIPPacket->xIPHeader ); UBaseType_t uxHeaderLength = ( UBaseType_t ) ( ( pxIPHeader->ucVersionHeaderLength & 0x0Fu ) << 2 ); uint8_t ucProtocol; + /* Bound the calculated header length: take away the Ethernet header size, + then check if the IP header is claiming to be longer than the remaining + total packet size. Also check for minimal header field length. */ + if( uxHeaderLength > pxNetworkBuffer->xDataLength - ipSIZE_OF_ETH_HEADER || + uxHeaderLength < ipSIZE_OF_IPv4_HEADER ) + { + return eReleaseBuffer; + } + ucProtocol = pxIPPacket->xIPHeader.ucProtocol; /* Check if the IP headers are acceptable and if it has our destination. */ eReturn = prvAllowIPPacket( pxIPPacket, pxNetworkBuffer, uxHeaderLength ); @@ -1520,15 +1535,21 @@ uint8_t ucProtocol; * Note: IP options are mostly use in Multi-cast protocols */ const size_t optlen = ( ( size_t ) uxHeaderLength ) - ipSIZE_OF_IPv4_HEADER; /* From: the previous start of UDP/ICMP/TCP data */ - uint8_t *pucSource = ( ( uint8_t * ) pxIPHeader ) + uxHeaderLength; + uint8_t *pucSource = ( uint8_t* )(pxNetworkBuffer->pucEthernetBuffer + sizeof( EthernetHeader_t ) + uxHeaderLength); /* To: the usual start of UDP/ICMP/TCP data at offset 20 from IP header */ - uint8_t *pucTarget = ( ( uint8_t * ) pxIPHeader ) + ipSIZE_OF_IPv4_HEADER; + uint8_t *pucTarget = ( uint8_t* )(pxNetworkBuffer->pucEthernetBuffer + sizeof( EthernetHeader_t ) + ipSIZE_OF_IPv4_HEADER); /* How many: total length minus the options and the lower headers */ const size_t xMoveLen = pxNetworkBuffer->xDataLength - optlen - ipSIZE_OF_IPv4_HEADER - ipSIZE_OF_ETH_HEADER; memmove( pucTarget, pucSource, xMoveLen ); pxNetworkBuffer->xDataLength -= optlen; + + /* Fix-up new version/header length field in IP packet. */ + pxIPHeader->ucVersionHeaderLength = + ( pxIPHeader->ucVersionHeaderLength & 0xF0 ) | /* High nibble is the version. */ + ( ( ipSIZE_OF_IPv4_HEADER >> 2 ) & 0x0F ); /* Low nibble is the header size, in bytes, divided by four. */ } + /* Add the IP and MAC addresses to the ARP table if they are not already there - otherwise refresh the age of the existing entry. */ @@ -1552,11 +1573,18 @@ uint8_t ucProtocol; be able to validate what it receives. */ #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) { - ICMPPacket_t *pxICMPPacket = ( ICMPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer ); - if( pxIPHeader->ulDestinationIPAddress == *ipLOCAL_IP_ADDRESS_POINTER ) - { - eReturn = prvProcessICMPPacket( pxICMPPacket ); - } + if( pxNetworkBuffer->xDataLength >= sizeof( ICMPPacket_t ) ) + { + ICMPPacket_t *pxICMPPacket = ( ICMPPacket_t * )( pxNetworkBuffer->pucEthernetBuffer ); + if( pxIPHeader->ulDestinationIPAddress == *ipLOCAL_IP_ADDRESS_POINTER ) + { + eReturn = prvProcessICMPPacket( pxICMPPacket ); + } + } + else + { + eReturn = eReleaseBuffer; + } } #endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */ break; @@ -1566,23 +1594,47 @@ uint8_t ucProtocol; /* The IP packet contained a UDP frame. */ UDPPacket_t *pxUDPPacket = ( UDPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer ); - /* Note the header values required prior to the - checksum generation as the checksum pseudo header - may clobber some of these values. */ - pxNetworkBuffer->xDataLength = FreeRTOS_ntohs( pxUDPPacket->xUDPHeader.usLength ) - sizeof( UDPHeader_t ); - /* HT:endian: fields in pxNetworkBuffer (usPort, ulIPAddress) were network order */ - pxNetworkBuffer->usPort = pxUDPPacket->xUDPHeader.usSourcePort; - pxNetworkBuffer->ulIPAddress = pxUDPPacket->xIPHeader.ulSourceIPAddress; - - /* ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM: - * In some cases, the upper-layer checksum has been calculated - * by the NIC driver */ - /* Pass the packet payload to the UDP sockets implementation. */ - /* HT:endian: xProcessReceivedUDPPacket wanted network order */ - if( xProcessReceivedUDPPacket( pxNetworkBuffer, pxUDPPacket->xUDPHeader.usDestinationPort ) == pdPASS ) - { - eReturn = eFrameConsumed; - } + /* Only proceed if the payload length indicated in the header + appears to be valid. */ + if ( pxNetworkBuffer->xDataLength >= sizeof( UDPPacket_t ) ) + { + /* Ensure that downstream UDP packet handling has the lesser + * of: the actual network buffer Ethernet frame length, or + * the sender's UDP packet header payload length, minus the + * size of the UDP header. + * + * The size of the UDP packet structure in this implementation + * includes the size of the Ethernet header, the size of + * the IP header, and the size of the UDP header. + */ + + pxNetworkBuffer->xDataLength -= sizeof( UDPPacket_t ); + if( ( FreeRTOS_ntohs( pxUDPPacket->xUDPHeader.usLength ) - sizeof( UDPHeader_t ) ) < + pxNetworkBuffer->xDataLength ) + { + pxNetworkBuffer->xDataLength = FreeRTOS_ntohs( pxUDPPacket->xUDPHeader.usLength ) - + sizeof( UDPHeader_t ); + } + + /* Fields in pxNetworkBuffer (usPort, ulIPAddress) are network order. */ + pxNetworkBuffer->usPort = pxUDPPacket->xUDPHeader.usSourcePort; + pxNetworkBuffer->ulIPAddress = pxUDPPacket->xIPHeader.ulSourceIPAddress; + + /* ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM: + * In some cases, the upper-layer checksum has been calculated + * by the NIC driver. + * + * Pass the packet payload to the UDP sockets implementation. */ + if( xProcessReceivedUDPPacket( pxNetworkBuffer, + pxUDPPacket->xUDPHeader.usDestinationPort ) == pdPASS ) + { + eReturn = eFrameConsumed; + } + } + else + { + eReturn = eReleaseBuffer; + } } break; @@ -1739,7 +1791,7 @@ uint8_t ucProtocol; #endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */ /*-----------------------------------------------------------*/ -uint16_t usGenerateProtocolChecksum( const uint8_t * const pucEthernetBuffer, BaseType_t xOutgoingPacket ) +uint16_t usGenerateProtocolChecksum( const uint8_t * const pucEthernetBuffer, size_t uxBufferLength, BaseType_t xOutgoingPacket ) { uint32_t ulLength; uint16_t usChecksum, *pusChecksum; @@ -1751,13 +1803,48 @@ uint8_t ucProtocol; const char *pcType; #endif - pxIPPacket = ( const IPPacket_t * ) pucEthernetBuffer; - uxIPHeaderLength = ( UBaseType_t ) ( 4u * ( pxIPPacket->xIPHeader.ucVersionHeaderLength & 0x0Fu ) ); /*_RB_ Why 4? */ - pxProtPack = ( ProtocolPacket_t * ) ( pucEthernetBuffer + ( uxIPHeaderLength - ipSIZE_OF_IPv4_HEADER ) ); - ucProtocol = pxIPPacket->xIPHeader.ucProtocol; + /* Check for minimum packet size. */ + if( uxBufferLength < sizeof( IPPacket_t ) ) + { + return ipINVALID_LENGTH; + } + /* Parse the packet length. */ + pxIPPacket = ( const IPPacket_t * ) pucEthernetBuffer; + + /* Per https://tools.ietf.org/html/rfc791, the four-bit Internet Header + Length field contains the length of the internet header in 32-bit words. */ + uxIPHeaderLength = ( UBaseType_t ) + ( sizeof( uint32_t ) * ( pxIPPacket->xIPHeader.ucVersionHeaderLength & 0x0Fu ) ); + + /* Check for minimum packet size. */ + if( uxBufferLength < sizeof( IPPacket_t ) + uxIPHeaderLength - ipSIZE_OF_IPv4_HEADER ) + { + return ipINVALID_LENGTH; + } + if( uxBufferLength < FreeRTOS_ntohs( pxIPPacket->xIPHeader.usLength ) ) + { + return ipINVALID_LENGTH; + } + + /* Identify the next protocol. */ + ucProtocol = pxIPPacket->xIPHeader.ucProtocol; + + /* N.B., if this IP packet header includes Options, then the following + assignment results in a pointer into the protocol packet with the Ethernet + and IP headers incorrectly aligned. However, either way, the "third" + protocol (Layer 3 or 4) header will be aligned, which is the convenience + of this calculation. */ + pxProtPack = ( ProtocolPacket_t * ) ( pucEthernetBuffer + ( uxIPHeaderLength - ipSIZE_OF_IPv4_HEADER ) ); + + /* Switch on the Layer 3/4 protocol. */ if( ucProtocol == ( uint8_t ) ipPROTOCOL_UDP ) { + if( uxBufferLength < uxIPHeaderLength + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_UDP_HEADER ) + { + return ipINVALID_LENGTH; + } + pusChecksum = ( uint16_t * ) ( &( pxProtPack->xUDPPacket.xUDPHeader.usChecksum ) ); #if( ipconfigHAS_DEBUG_PRINTF != 0 ) { @@ -1767,7 +1854,12 @@ uint8_t ucProtocol; } else if( ucProtocol == ( uint8_t ) ipPROTOCOL_TCP ) { - pusChecksum = ( uint16_t * ) ( &( pxProtPack->xTCPPacket.xTCPHeader.usChecksum ) ); + if( uxBufferLength < uxIPHeaderLength + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_TCP_HEADER ) + { + return ipINVALID_LENGTH; + } + + pusChecksum = ( uint16_t * ) ( &( pxProtPack->xTCPPacket.xTCPHeader.usChecksum ) ); #if( ipconfigHAS_DEBUG_PRINTF != 0 ) { pcType = "TCP"; @@ -1777,8 +1869,12 @@ uint8_t ucProtocol; else if( ( ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP ) || ( ucProtocol == ( uint8_t ) ipPROTOCOL_IGMP ) ) { - pusChecksum = ( uint16_t * ) ( &( pxProtPack->xICMPPacket.xICMPHeader.usChecksum ) ); - + if( uxBufferLength < uxIPHeaderLength + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_ICMP_HEADER ) + { + return ipINVALID_LENGTH; + } + + pusChecksum = ( uint16_t * ) ( &( pxProtPack->xICMPPacket.xICMPHeader.usChecksum ) ); #if( ipconfigHAS_DEBUG_PRINTF != 0 ) { if( ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP ) @@ -1798,6 +1894,8 @@ uint8_t ucProtocol; return ipUNHANDLED_PROTOCOL; } + /* The protocol and checksum field have been identified. Check the direction + of the packet. */ if( xOutgoingPacket != pdFALSE ) { /* This is an outgoing packet. Before calculating the checksum, set it @@ -1844,7 +1942,7 @@ uint8_t ucProtocol; /* And then continue at the IPv4 source and destination addresses. */ usChecksum = ( uint16_t ) ( ~usGenerateChecksum( ( uint32_t ) usChecksum, ( uint8_t * )&( pxIPPacket->xIPHeader.ulSourceIPAddress ), - ( size_t )( 2u * sizeof( pxIPPacket->xIPHeader.ulSourceIPAddress ) + ulLength ) ) ); + ( 2u * sizeof( pxIPPacket->xIPHeader.ulSourceIPAddress ) + ulLength ) ) ); /* Sum TCP header and data. */ } @@ -1897,6 +1995,39 @@ uint8_t ucProtocol; } /*-----------------------------------------------------------*/ +/** + * This method generates a checksum for a given IPv4 header, per RFC791 (page 14). + * The checksum algorithm is decribed as: + * "[T]he 16 bit one's complement of the one's complement sum of all 16 bit words in the + * header. For purposes of computing the checksum, the value of the checksum field is zero." + * + * In a nutshell, that means that each 16-bit 'word' must be summed, after which + * the number of 'carries' (overflows) is added to the result. If that addition + * produces an overflow, that 'carry' must also be added to the final result. The final checksum + * should be the bitwise 'not' (ones-complement) of the result if the packet is + * meant to be transmitted, but this method simply returns the raw value, probably + * because when a packet is received, the checksum is verified by checking that + * ((received & calculated) == 0) without applying a bitwise 'not' to the 'calculated' checksum. + * + * This logic is optimized for microcontrollers which have limited resources, so the logic looks odd. + * It iterates over the full range of 16-bit words, but it does so by processing several 32-bit + * words at once whenever possible. Its first step is to align the memory pointer to a 32-bit boundary, + * after which it runs a fast loop to process multiple 32-bit words at once and adding their 'carries'. + * Finally, it finishes up by processing any remaining 16-bit words, and adding up all of the 'carries'. + * With 32-bit arithmetic, the number of 16-bit 'carries' produced by sequential additions can be found + * by looking at the 16 most-significant bits of the 32-bit integer, since a 32-bit int will continue + * counting up instead of overflowing after 16 bits. That is why the actual checksum calculations look like: + * union.u32 = ( uint32_t ) union.u16[ 0 ] + union.u16[ 1 ]; + * + * Arguments: + * ulSum: This argument provides a value to initialize the progressive summation + * of the header's values to. It is often 0, but protocols like TCP or UDP + * can have pseudo-header fields which need to be included in the checksum. + * pucNextData: This argument contains the address of the first byte which this + * method should process. The method's memory iterator is initialized to this value. + * uxDataLengthBytes: This argument contains the number of bytes that this method + * should process. + */ uint16_t usGenerateChecksum( uint32_t ulSum, const uint8_t * pucNextData, size_t uxDataLengthBytes ) { xUnion32 xSum2, xSum, xTerm; @@ -2095,8 +2226,8 @@ uint32_t FreeRTOS_GetNetmask( void ) void FreeRTOS_UpdateMACAddress( const uint8_t ucMACAddress[ipMAC_ADDRESS_LENGTH_BYTES] ) { - /* Copy the MAC address at the start of the default packet header fragment. */ - memcpy( ( void * )ipLOCAL_MAC_ADDRESS, ( void * )ucMACAddress, ( size_t )ipMAC_ADDRESS_LENGTH_BYTES ); + /* Copy the MAC address at the start of the default packet header fragment. */ + memcpy( ( void * )ipLOCAL_MAC_ADDRESS, ( void * )ucMACAddress, ( size_t )ipMAC_ADDRESS_LENGTH_BYTES ); } /*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_Sockets.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_Sockets.c index be8dec62c..6ad9a86d3 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_Sockets.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_Sockets.c @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.3 + * FreeRTOS+TCP V2.0.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 @@ -54,18 +54,16 @@ xBoundUDPSocketsList or xBoundTCPSocketsList */ number then, depending on the FreeRTOSIPConfig.h settings, it might be that a port number is automatically generated for the socket. Automatically generated port numbers will be between socketAUTO_PORT_ALLOCATION_START_NUMBER and -0xffff. */ -/* _HT_ thinks that the default of 0xc000 is pretty high */ +0xffff. + +Per https://tools.ietf.org/html/rfc6056, "the dynamic ports consist of the range +49152-65535. However, ephemeral port selection algorithms should use the whole +range 1024-65535" excluding those already in use (inbound or outbound). */ #if !defined( socketAUTO_PORT_ALLOCATION_START_NUMBER ) - #define socketAUTO_PORT_ALLOCATION_START_NUMBER ( ( uint16_t ) 0xc000 ) + #define socketAUTO_PORT_ALLOCATION_START_NUMBER ( ( uint16_t ) 0x0400 ) #endif -/* When the automatically generated port numbers overflow, the next value used -is not set back to socketAUTO_PORT_ALLOCATION_START_NUMBER because it is likely -that the first few automatically generated ports will still be in use. Instead -it is reset back to the value defined by this constant. */ -#define socketAUTO_PORT_ALLOCATION_RESET_NUMBER ( ( uint16_t ) 0xc100 ) -#define socketAUTO_PORT_ALLOCATION_MAX_NUMBER ( ( uint16_t ) 0xff00 ) +#define socketAUTO_PORT_ALLOCATION_MAX_NUMBER ( ( uint16_t ) 0xffff ) /* The number of octets that make up an IP address. */ #define socketMAX_IP_ADDRESS_OCTETS 4u @@ -165,15 +163,6 @@ List_t xBoundUDPSocketsList; List_t xBoundTCPSocketsList; #endif /* ipconfigUSE_TCP == 1 */ -/* Holds the next private port number to use when binding a client socket for -UDP, and if ipconfigUSE_TCP is set to 1, also TCP. UDP uses index -socketNEXT_UDP_PORT_NUMBER_INDEX and TCP uses index -socketNEXT_TCP_PORT_NUMBER_INDEX. The initial value is set to be between -socketAUTO_PORT_ALLOCATION_RESET_NUMBER and socketAUTO_PORT_ALLOCATION_MAX_NUMBER -when the IP stack is initialised. Note ipconfigRAND32() is used, which must be -seeded prior to the IP task being started. */ -static uint16_t usNextPortToUse[ socketPROTOCOL_COUNT ] = { 0 }; - /*-----------------------------------------------------------*/ static BaseType_t prvValidSocket( FreeRTOS_Socket_t *pxSocket, BaseType_t xProtocol, BaseType_t xIsBound ) @@ -199,35 +188,17 @@ BaseType_t xReturn = pdTRUE; } /*-----------------------------------------------------------*/ -void vNetworkSocketsInit( void ) +BaseType_t vNetworkSocketsInit( void ) { -const uint32_t ulAutoPortRange = socketAUTO_PORT_ALLOCATION_MAX_NUMBER - socketAUTO_PORT_ALLOCATION_RESET_NUMBER; -uint32_t ulRandomPort; - - vListInitialise( &xBoundUDPSocketsList ); - - /* Determine the first anonymous UDP port number to get assigned. Give it - a random value in order to avoid confusion about port numbers being used - earlier, before rebooting the device. Start with the first auto port - number, then add a random offset up to a maximum of the range of numbers. */ - ulRandomPort = socketAUTO_PORT_ALLOCATION_START_NUMBER; - ulRandomPort += ( ipconfigRAND32() % ulAutoPortRange ); - usNextPortToUse[ socketNEXT_UDP_PORT_NUMBER_INDEX ] = ( uint16_t ) ulRandomPort; - - #if( ipconfigUSE_TCP == 1 ) - { - extern uint32_t ulNextInitialSequenceNumber; + vListInitialise( &xBoundUDPSocketsList ); - ulNextInitialSequenceNumber = ipconfigRAND32(); + #if( ipconfigUSE_TCP == 1 ) + { + vListInitialise( &xBoundTCPSocketsList ); + } + #endif /* ipconfigUSE_TCP == 1 */ - /* Determine the first anonymous TCP port number to get assigned. */ - ulRandomPort = socketAUTO_PORT_ALLOCATION_START_NUMBER; - ulRandomPort += ( ipconfigRAND32() % ulAutoPortRange ); - usNextPortToUse[ socketNEXT_TCP_PORT_NUMBER_INDEX ] = ( uint16_t ) ulRandomPort; - - vListInitialise( &xBoundTCPSocketsList ); - } - #endif /* ipconfigUSE_TCP == 1 */ + return pdTRUE; } /*-----------------------------------------------------------*/ @@ -261,6 +232,7 @@ FreeRTOS_Socket_t *pxSocket; if( xType != FREERTOS_SOCK_DGRAM ) { xReturn = pdFAIL; + configASSERT( xReturn ); } /* In case a UDP socket is created, do not allocate space for TCP data. */ *pxSocketSize = ( sizeof( *pxSocket ) - sizeof( pxSocket->u ) ) + sizeof( pxSocket->u.xUDP ); @@ -271,6 +243,7 @@ FreeRTOS_Socket_t *pxSocket; if( xType != FREERTOS_SOCK_STREAM ) { xReturn = pdFAIL; + configASSERT( xReturn ); } *pxSocketSize = ( sizeof( *pxSocket ) - sizeof( pxSocket->u ) ) + sizeof( pxSocket->u.xTCP ); @@ -279,6 +252,7 @@ FreeRTOS_Socket_t *pxSocket; else { xReturn = pdFAIL; + configASSERT( xReturn ); } } /* In case configASSERT() is not used */ @@ -320,7 +294,7 @@ Socket_t xReturn; } else { - /* Clear the entire space to avoid nulling individual entries. */ + /* Clear the entire space to avoid nulling individual entries */ memset( pxSocket, '\0', uxSocketSize ); pxSocket->xEventGroup = xEventGroup; @@ -1016,14 +990,12 @@ List_t *pxSocketList; #if( ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 ) { /* pxAddress will be NULL if sendto() was called on a socket without the - socket being bound to an address. In this case, automatically allocate - an address to the socket. There is a very tiny chance that the allocated - port will already be in use - if that is the case, then the check below - [pxListFindListItemWithValue()] will result in an error being returned. */ + socket being bound to an address. In this case, automatically allocate + an address and port to the socket. */ if( pxAddress == NULL ) { pxAddress = &xAddress; - /* For now, put it to zero, will be assigned later */ + /* Put the port to zero to be assigned later. */ pxAddress->sin_port = 0u; } } @@ -1037,7 +1009,11 @@ List_t *pxSocketList; { if( pxAddress->sin_port == 0u ) { - pxAddress->sin_port = prvGetPrivatePortNumber( ( BaseType_t ) pxSocket->ucProtocol ); + pxAddress->sin_port = prvGetPrivatePortNumber( ( BaseType_t )pxSocket->ucProtocol ); + if( 0 == pxAddress->sin_port ) + { + return -pdFREERTOS_ERRNO_EADDRNOTAVAIL; + } } /* If vSocketBind() is called from the API FreeRTOS_bind() it has been @@ -1524,7 +1500,7 @@ FreeRTOS_Socket_t *pxSocket; if( pxSocket->u.xTCP.xTCPWindow.u.bits.bHasInit != pdFALSE_UNSIGNED ) { pxSocket->u.xTCP.xTCPWindow.xSize.ulRxWindowLength = pxSocket->u.xTCP.uxRxWinSize * pxSocket->u.xTCP.usInitMSS; - pxSocket->u.xTCP.xTCPWindow.xSize.ulRxWindowLength = pxSocket->u.xTCP.uxTxWinSize * pxSocket->u.xTCP.usInitMSS; + pxSocket->u.xTCP.xTCPWindow.xSize.ulTxWindowLength = pxSocket->u.xTCP.uxTxWinSize * pxSocket->u.xTCP.usInitMSS; } } @@ -1631,54 +1607,77 @@ FreeRTOS_Socket_t *pxSocket; /*-----------------------------------------------------------*/ -/* Get a free private ('anonymous') port number */ +/* Find an available port number per https://tools.ietf.org/html/rfc6056. */ static uint16_t prvGetPrivatePortNumber( BaseType_t xProtocol ) { -uint16_t usResult; -BaseType_t xIndex; +const uint16_t usEphemeralPortCount = + socketAUTO_PORT_ALLOCATION_MAX_NUMBER - socketAUTO_PORT_ALLOCATION_START_NUMBER + 1; +uint16_t usIterations = usEphemeralPortCount; +uint32_t ulRandomSeed = 0; +uint16_t usResult = 0; +BaseType_t xGotZeroOnce = pdFALSE; const List_t *pxList; #if ipconfigUSE_TCP == 1 if( xProtocol == ( BaseType_t ) FREERTOS_IPPROTO_TCP ) { - xIndex = socketNEXT_TCP_PORT_NUMBER_INDEX; pxList = &xBoundTCPSocketsList; } else #endif { - xIndex = socketNEXT_UDP_PORT_NUMBER_INDEX; pxList = &xBoundUDPSocketsList; } /* Avoid compiler warnings if ipconfigUSE_TCP is not defined. */ ( void ) xProtocol; - /* Assign the next port in the range. Has it overflowed? */ - /*_RB_ This needs to be randomised rather than sequential. */ - /* _HT_ Agreed, although many OS's use sequential port numbers, see - https://www.cymru.com/jtk/misc/ephemeralports.html */ - for ( ;; ) - { - ++( usNextPortToUse[ xIndex ] ); - - if( usNextPortToUse[ xIndex ] >= socketAUTO_PORT_ALLOCATION_MAX_NUMBER ) - { - /* Don't go right back to the start of the dynamic/private port - range numbers as any persistent sockets are likely to have been - create first so the early port numbers may still be in use. */ - usNextPortToUse[ xIndex ] = socketAUTO_PORT_ALLOCATION_RESET_NUMBER; - } - - usResult = FreeRTOS_htons( usNextPortToUse[ xIndex ] ); - - if( pxListFindListItemWithValue( pxList, ( TickType_t ) usResult ) == NULL ) - { - break; - } - } - return usResult; -} /* Tested */ + /* Find the next available port using the random seed as a starting + point. */ + do + { + /* Generate a random seed. */ + ulRandomSeed = ipconfigRAND32( ); + + /* Only proceed if the random number generator succeeded. */ + if( 0 == ulRandomSeed ) + { + if( pdFALSE == xGotZeroOnce ) + { + xGotZeroOnce = pdTRUE; + continue; + } + else + { + break; + } + } + + /* Map the random to a candidate port. */ + usResult = + socketAUTO_PORT_ALLOCATION_START_NUMBER + + ( ( ( uint16_t )ulRandomSeed ) % usEphemeralPortCount ); + + /* Check if there's already an open socket with the same protocol + and port. */ + if( NULL == pxListFindListItemWithValue( + pxList, + ( TickType_t )FreeRTOS_htons( usResult ) ) ) + { + usResult = FreeRTOS_htons( usResult ); + break; + } + else + { + usResult = 0; + } + + usIterations--; + } + while( usIterations > 0 ); + + return usResult; +} /*-----------------------------------------------------------*/ /* pxListFindListItemWithValue: find a list item in a bound socket list @@ -1889,7 +1888,7 @@ void vSocketWakeUpUser( FreeRTOS_Socket_t *pxSocket ) /* This define makes it possible for network-card drivers to inspect * UDP message and see if there is any UDP socket bound to a given port * number. - * This is probably only useful in systems with a minimum of RAM and + * This is probably only usefull in systems with a minimum of RAM and * when lots of anonymous broadcast messages come in */ BaseType_t xPortHasUDPSocket( uint16_t usPortNr ) @@ -2374,9 +2373,7 @@ void vSocketWakeUpUser( FreeRTOS_Socket_t *pxSocket ) { xResult = -pdFREERTOS_ERRNO_ENOMEM; } - else if( ( pxSocket->u.xTCP.ucTCPState == eCLOSED ) || - ( pxSocket->u.xTCP.ucTCPState == eCLOSE_WAIT ) || - ( pxSocket->u.xTCP.ucTCPState == eCLOSING ) ) + else if( pxSocket->u.xTCP.ucTCPState == eCLOSED ) { xResult = -pdFREERTOS_ERRNO_ENOTCONN; } @@ -2875,7 +2872,7 @@ void vSocketWakeUpUser( FreeRTOS_Socket_t *pxSocket ) #if( ipconfigUSE_TCP == 1 ) - static StreamBuffer_t *prvTCPCreateStream( FreeRTOS_Socket_t *pxSocket, BaseType_t xIsInputStream ) + static StreamBuffer_t *prvTCPCreateStream ( FreeRTOS_Socket_t *pxSocket, BaseType_t xIsInputStream ) { StreamBuffer_t *pxBuffer; size_t uxLength; @@ -2885,26 +2882,11 @@ void vSocketWakeUpUser( FreeRTOS_Socket_t *pxSocket ) creation, it could still be changed with setsockopt(). */ if( xIsInputStream != pdFALSE ) { - /* Flow control for input streams works with a low- and a high-water mark. - 1) If the RX-space becomes less than uxLittleSpace, the flag 'bLowWater' will - be set, and a TCP window update message will be sent to the peer. - 2) The data will be read from the socket by recv() and when RX-space becomes - larger than or equal to than 'uxEnoughSpace', a new TCP window update - message will be sent to the peer, and 'bLowWater' will get cleared again. - By default: - uxLittleSpace == 1/5 x uxRxStreamSize - uxEnoughSpace == 4/5 x uxRxStreamSize - How-ever it is very inefficient to make 'uxLittleSpace' smaller than the actual MSS. - */ uxLength = pxSocket->u.xTCP.uxRxStreamSize; if( pxSocket->u.xTCP.uxLittleSpace == 0ul ) { pxSocket->u.xTCP.uxLittleSpace = ( 1ul * pxSocket->u.xTCP.uxRxStreamSize ) / 5u; /*_RB_ Why divide by 5? Can this be changed to a #define? */ - if( ( pxSocket->u.xTCP.uxLittleSpace < pxSocket->u.xTCP.usCurMSS ) && ( pxSocket->u.xTCP.uxRxStreamSize >= 2u * pxSocket->u.xTCP.usCurMSS ) ) - { - pxSocket->u.xTCP.uxLittleSpace = pxSocket->u.xTCP.usCurMSS; - } } if( pxSocket->u.xTCP.uxEnoughSpace == 0ul ) @@ -3047,10 +3029,8 @@ void vSocketWakeUpUser( FreeRTOS_Socket_t *pxSocket ) break; } - if( pxSocket->u.xTCP.pxHandleReceive( (Socket_t *)pxSocket, ( void* )ucReadPtr, ( size_t ) ulCount ) != pdFALSE ) - { - uxStreamBufferGet( pxStream, 0ul, NULL, ( size_t ) ulCount, pdFALSE ); - } + pxSocket->u.xTCP.pxHandleReceive( (Socket_t *)pxSocket, ( void* )ucReadPtr, ( size_t ) ulCount ); + uxStreamBufferGet( pxStream, 0ul, NULL, ( size_t ) ulCount, pdFALSE ); } } else #endif /* ipconfigUSE_CALLBACKS */ @@ -3378,12 +3358,13 @@ void vSocketWakeUpUser( FreeRTOS_Socket_t *pxSocket ) char ucChildText[16] = ""; if (pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN) { - snprintf( ucChildText, sizeof( ucChildText ), " %d/%d", - pxSocket->u.xTCP.usChildCount, - pxSocket->u.xTCP.usBacklog); + const int32_t copied_len = snprintf( ucChildText, sizeof( ucChildText ), " %d/%d", + ( int ) pxSocket->u.xTCP.usChildCount, + ( int ) pxSocket->u.xTCP.usBacklog); + /* These should never evaluate to false since the buffers are both shorter than 5-6 characters (<=65535) */ + configASSERT( copied_len >= 0 ); + configASSERT( copied_len < sizeof( ucChildText ) ); } - if( age > 999999 ) - age = 999999; FreeRTOS_printf( ( "TCP %5d %-16lxip:%5d %d/%d %-13.13s %6lu %6u%s\n", pxSocket->usLocalPort, /* Local port on this machine */ pxSocket->u.xTCP.ulRemoteIP, /* IP address of remote machine */ @@ -3391,7 +3372,7 @@ void vSocketWakeUpUser( FreeRTOS_Socket_t *pxSocket ) pxSocket->u.xTCP.rxStream != NULL, pxSocket->u.xTCP.txStream != NULL, FreeRTOS_GetTCPStateName( pxSocket->u.xTCP.ucTCPState ), - age, + (age > 999999 ? 999999 : age), /* Format 'age' for printing */ pxSocket->u.xTCP.usTimeout, ucChildText ) ); /* Remove compiler warnings if FreeRTOS_debug_printf() is not defined. */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_Stream_Buffer.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_Stream_Buffer.c index 91e5fae03..7729582e5 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_Stream_Buffer.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_Stream_Buffer.c @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.3 + * FreeRTOS+TCP V2.0.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 diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_IP.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_IP.c index 614829ff9..b8a6be04e 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_IP.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_IP.c @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.3 + * FreeRTOS+TCP V2.0.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 @@ -61,7 +61,7 @@ /* This compile-time test was moved to here because some macro's were unknown within 'FreeRTOSIPConfigDefaults.h'. It tests whether -the defined MTU size can contain at ;east a complete TCP packet. */ +the defined MTU size can contain at least a complete TCP packet. */ #if ( ( ipconfigTCP_MSS + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) > ipconfigNETWORK_MTU ) #error The ipconfigTCP_MSS setting in FreeRTOSIPConfig.h is too large. @@ -137,13 +137,6 @@ the defined MTU size can contain at ;east a complete TCP packet. */ */ #define REDUCED_MSS_THROUGH_INTERNET ( 1400 ) -/* - * Each time a new TCP connection is being made, a new Initial Sequence Number shall be used. - * The variable 'ulNextInitialSequenceNumber' will be incremented with a recommended value - * of 0x102. - */ -#define INITIAL_SEQUENCE_NUMBER_INCREMENT ( 0x102UL ) - /* * When there are no TCP options, the TCP offset equals 20 bytes, which is stored as * the number 5 (words) in the higher niblle of the TCP-offset byte. @@ -269,10 +262,6 @@ static void prvTCPAddTxData( FreeRTOS_Socket_t *pxSocket ); */ static BaseType_t prvTCPHandleFin( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer ); -#if( ipconfigUSE_TCP_TIMESTAMPS == 1 ) - static UBaseType_t prvTCPSetTimeStamp( BaseType_t lOffset, FreeRTOS_Socket_t *pxSocket, TCPHeader_t *pxTCPHeader ); -#endif - /* * Called from prvTCPHandleState(). Find the TCP payload data and check and * return its length. @@ -360,12 +349,14 @@ static NetworkBufferDescriptor_t *prvTCPBufferResize( FreeRTOS_Socket_t *pxSocke static uint8_t prvWinScaleFactor( FreeRTOS_Socket_t *pxSocket ); #endif -/*-----------------------------------------------------------*/ - -/* Initial Sequence Number, i.e. the next initial sequence number that will be -used when a new connection is opened. The value should be randomized to prevent -attacks from outside (spoofing). */ -uint32_t ulNextInitialSequenceNumber = 0ul; +/* + * Generate a randomized TCP Initial Sequence Number per RFC. + */ +extern uint32_t ulApplicationGetNextSequenceNumber( + uint32_t ulSourceAddress, + uint16_t usSourcePort, + uint32_t ulDestinationAddress, + uint16_t usDestinationPort ); /*-----------------------------------------------------------*/ @@ -480,11 +471,11 @@ BaseType_t xReady = pdFALSE; if( ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) && ( pxSocket->u.xTCP.txStream != NULL ) ) { /* The API FreeRTOS_send() might have added data to the TX stream. Add - this data to the windowing system so it can be transmitted. */ + this data to the windowing system to it can be transmitted. */ prvTCPAddTxData( pxSocket ); } - #if( ipconfigUSE_TCP_WIN == 1 ) + #if ipconfigUSE_TCP_WIN == 1 { if( pxSocket->u.xTCP.pxAckMessage != NULL ) { @@ -577,7 +568,7 @@ NetworkBufferDescriptor_t *pxNetworkBuffer; if( pxSocket->u.xTCP.ucTCPState != eCONNECT_SYN ) { - /* The connection is in a state other than SYN. */ + /* The connection is in s state other than SYN. */ pxNetworkBuffer = NULL; /* prvTCPSendRepeated() will only create a network buffer if necessary, @@ -609,18 +600,6 @@ NetworkBufferDescriptor_t *pxNetworkBuffer; the Ethernet address of the peer or the gateway is found. */ pxTCPPacket = ( TCPPacket_t * )pxSocket->u.xTCP.xPacket.u.ucLastPacket; - #if( ipconfigUSE_TCP_TIMESTAMPS == 1 ) - { - /* When TCP time stamps are enabled, but they will only be applied - if the peer is outside the netmask, usually on the internet. - Packages sent on a LAN are usually too big to carry time stamps. */ - if( ( ( pxSocket->u.xTCP.ulRemoteIP ^ FreeRTOS_ntohl( *ipLOCAL_IP_ADDRESS_POINTER ) ) & xNetworkAddressing.ulNetMask ) != 0ul ) - { - pxSocket->u.xTCP.xTCPWindow.u.bits.bTimeStamps = pdTRUE_UNSIGNED; - } - } - #endif - /* About to send a SYN packet. Call prvSetSynAckOptions() to set the proper options: The size of MSS and whether SACK's are allowed. */ @@ -707,12 +686,15 @@ NetworkBufferDescriptor_t xTempBuffer; if( pxNetworkBuffer == NULL ) { - memset( &xTempBuffer, '\0', sizeof( xTempBuffer ) ); pxNetworkBuffer = &xTempBuffer; + #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 ) + { + xTempBuffer.pxNextBuffer = NULL; + } + #endif xTempBuffer.pucEthernetBuffer = pxSocket->u.xTCP.xPacket.u.ucLastPacket; xTempBuffer.xDataLength = sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ); - /* A pseudo network buffer can not be released. */ xReleaseAfterSend = pdFALSE; } @@ -903,7 +885,7 @@ NetworkBufferDescriptor_t xTempBuffer; pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum ); /* calculate the TCP checksum for an outgoing packet. */ - usGenerateProtocolChecksum( (uint8_t*)pxTCPPacket, pdTRUE ); + usGenerateProtocolChecksum( (uint8_t*)pxTCPPacket, pxNetworkBuffer->xDataLength, pdTRUE ); /* A calculated checksum of 0 must be inverted as 0 means the checksum is disabled. */ @@ -914,11 +896,9 @@ NetworkBufferDescriptor_t xTempBuffer; } #endif - #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 ) - { - pxNetworkBuffer->pxNextBuffer = NULL; - } - #endif + #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 ) + pxNetworkBuffer->pxNextBuffer = NULL; + #endif /* Important: tell NIC driver how many bytes must be sent. */ pxNetworkBuffer->xDataLength = ulLen + ipSIZE_OF_ETH_HEADER; @@ -928,7 +908,7 @@ NetworkBufferDescriptor_t xTempBuffer; sizeof( pxEthernetHeader->xDestinationAddress ) ); /* The source MAC addresses is fixed to 'ipLOCAL_MAC_ADDRESS'. */ - memcpy( ( void * ) &( pxEthernetHeader->xSourceAddress ), ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES ); + memcpy( ( void * ) &( pxEthernetHeader->xSourceAddress) , ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES ); #if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES ) { @@ -1002,6 +982,7 @@ eARPLookupResult_t eReturned; uint32_t ulRemoteIP; MACAddress_t xEthAddress; BaseType_t xReturn = pdTRUE; +uint32_t ulInitialSequenceNumber = 0; #if( ipconfigHAS_PRINTF != 0 ) { @@ -1017,31 +998,46 @@ BaseType_t xReturn = pdTRUE; switch( eReturned ) { - case eARPCacheHit: /* An ARP table lookup found a valid entry. */ - break; /* We can now prepare the SYN packet. */ - case eARPCacheMiss: /* An ARP table lookup did not find a valid entry. */ - case eCantSendPacket: /* There is no IP address, or an ARP is still in progress. */ - default: - /* Count the number of times it couldn't find the ARP address. */ - pxSocket->u.xTCP.ucRepCount++; + case eARPCacheHit: /* An ARP table lookup found a valid entry. */ + break; /* We can now prepare the SYN packet. */ + case eARPCacheMiss: /* An ARP table lookup did not find a valid entry. */ + case eCantSendPacket: /* There is no IP address, or an ARP is still in progress. */ + default: + /* Count the number of times it couldn't find the ARP address. */ + pxSocket->u.xTCP.ucRepCount++; - FreeRTOS_debug_printf( ( "ARP for %lxip (using %lxip): rc=%d %02X:%02X:%02X %02X:%02X:%02X\n", - pxSocket->u.xTCP.ulRemoteIP, - FreeRTOS_htonl( ulRemoteIP ), - eReturned, - xEthAddress.ucBytes[ 0 ], - xEthAddress.ucBytes[ 1 ], - xEthAddress.ucBytes[ 2 ], - xEthAddress.ucBytes[ 3 ], - xEthAddress.ucBytes[ 4 ], - xEthAddress.ucBytes[ 5 ] ) ); - - /* And issue a (new) ARP request */ - FreeRTOS_OutputARPRequest( ulRemoteIP ); - - xReturn = pdFALSE; - break; - } + FreeRTOS_debug_printf( ( "ARP for %lxip (using %lxip): rc=%d %02X:%02X:%02X %02X:%02X:%02X\n", + pxSocket->u.xTCP.ulRemoteIP, + FreeRTOS_htonl( ulRemoteIP ), + eReturned, + xEthAddress.ucBytes[ 0 ], + xEthAddress.ucBytes[ 1 ], + xEthAddress.ucBytes[ 2 ], + xEthAddress.ucBytes[ 3 ], + xEthAddress.ucBytes[ 4 ], + xEthAddress.ucBytes[ 5 ] ) ); + + /* And issue a (new) ARP request */ + FreeRTOS_OutputARPRequest( ulRemoteIP ); + + xReturn = pdFALSE; + } + + if( xReturn != pdFALSE ) + { + /* Get a difficult-to-predict initial sequence number for this 4-tuple. */ + ulInitialSequenceNumber = ulApplicationGetNextSequenceNumber( + *ipLOCAL_IP_ADDRESS_POINTER, + pxSocket->usLocalPort, + pxSocket->u.xTCP.ulRemoteIP, + pxSocket->u.xTCP.usRemotePort ); + + /* Check for a random number generation error. */ + if( 0 == ulInitialSequenceNumber ) + { + xReturn = pdFALSE; + } + } if( xReturn != pdFALSE ) { @@ -1050,10 +1046,10 @@ BaseType_t xReturn = pdTRUE; pxTCPPacket = ( TCPPacket_t * )pxSocket->u.xTCP.xPacket.u.ucLastPacket; pxIPHeader = &pxTCPPacket->xIPHeader; - /* Reset the retry counter to zero... */ + /* reset the retry counter to zero. */ pxSocket->u.xTCP.ucRepCount = 0u; - /* ...and remember that the connect/SYN data are prepared. */ + /* And remember that the connect/SYN data are prepared. */ pxSocket->u.xTCP.bits.bConnPrepared = pdTRUE_UNSIGNED; /* Now that the Ethernet address is known, the initial packet can be @@ -1086,11 +1082,7 @@ BaseType_t xReturn = pdTRUE; pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber = 0ul; /* Start with ISN (Initial Sequence Number). */ - pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber = ulNextInitialSequenceNumber; - - /* And increment it with 268 for the next new connection, which is - recommended value. */ - ulNextInitialSequenceNumber += 0x102UL; + pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber = ulInitialSequenceNumber; /* The TCP header size is 20 bytes, divided by 4 equals 5, which is put in the high nibble of the TCP offset field. */ @@ -1160,38 +1152,73 @@ UBaseType_t uxNewMSS; pucLast = pucPtr + (((pxTCPHeader->ucTCPOffset >> 4) - 5) << 2); pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow; + /* Validate options size calculation. */ + if( pucLast > ( pxNetworkBuffer->pucEthernetBuffer + pxNetworkBuffer->xDataLength ) ) + { + return; + } + /* The comparison with pucLast is only necessary in case the option data are corrupted, we don't like to run into invalid memory and crash. */ while( pucPtr < pucLast ) { + UBaseType_t xRemainingOptionsBytes = pucLast - pucPtr; + if( pucPtr[ 0 ] == TCP_OPT_END ) { /* End of options. */ - return; + break; } if( pucPtr[ 0 ] == TCP_OPT_NOOP) { - pucPtr++; - - /* NOP option, inserted to make the length a multiple of 4. */ + /* NOP option, inserted to make the length a multiple of 4. */ + pucPtr++; + continue; } + + /* Any other well-formed option must be at least two bytes: the option + type byte followed by a length byte. */ + if( xRemainingOptionsBytes < 2 ) + { + break; + } #if( ipconfigUSE_TCP_WIN != 0 ) - else if( ( pucPtr[ 0 ] == TCP_OPT_WSOPT ) && ( pucPtr[ 1 ] == TCP_OPT_WSOPT_LEN ) ) + else if( pucPtr[ 0 ] == TCP_OPT_WSOPT ) { + /* Confirm that the option fits in the remaining buffer space. */ + if( xRemainingOptionsBytes < TCP_OPT_WSOPT_LEN || + pucPtr[ 1 ] != TCP_OPT_WSOPT_LEN ) + { + break; + } + pxSocket->u.xTCP.ucPeerWinScaleFactor = pucPtr[ 2 ]; pxSocket->u.xTCP.bits.bWinScaling = pdTRUE_UNSIGNED; pucPtr += TCP_OPT_WSOPT_LEN; } #endif /* ipconfigUSE_TCP_WIN */ - else if( ( pucPtr[ 0 ] == TCP_OPT_MSS ) && ( pucPtr[ 1 ] == TCP_OPT_MSS_LEN ) ) - { - /* An MSS option with the correct option length. FreeRTOS_htons() + else if( pucPtr[ 0 ] == TCP_OPT_MSS ) + { + /* Confirm that the option fits in the remaining buffer space. */ + if( xRemainingOptionsBytes < TCP_OPT_MSS_LEN || + pucPtr[ 1 ] != TCP_OPT_MSS_LEN ) + { + break; + } + + /* An MSS option with the correct option length. FreeRTOS_htons() is not needed here because usChar2u16() already returns a host endian number. */ uxNewMSS = usChar2u16( pucPtr + 2 ); if( pxSocket->u.xTCP.usInitMSS != uxNewMSS ) { + /* Perform a basic check on the the new MSS. */ + if( uxNewMSS == 0 ) + { + break; + } + FreeRTOS_debug_printf( ( "MSS change %u -> %lu\n", pxSocket->u.xTCP.usInitMSS, uxNewMSS ) ); } @@ -1225,11 +1252,11 @@ UBaseType_t uxNewMSS; { /* All other options have a length field, so that we easily can skip past them. */ - int len = ( int )pucPtr[ 1 ]; - if( len == 0 ) + unsigned char len = pucPtr[ 1 ]; + if( len < 2 || len > xRemainingOptionsBytes ) { - /* If the length field is zero, the options are malformed - and we don't process them further. */ + /* If the length field is too small or too big, the options are malformed. + Don't process them further. */ break; } @@ -1284,16 +1311,6 @@ UBaseType_t uxNewMSS; } /* len should be 0 by now. */ } - #if ipconfigUSE_TCP_TIMESTAMPS == 1 - else if( pucPtr[0] == TCP_OPT_TIMESTAMP ) - { - len -= 2; /* Skip option and length byte. */ - pucPtr += 2; - pxSocket->u.xTCP.xTCPWindow.u.bits.bTimeStamps = pdTRUE_UNSIGNED; - pxSocket->u.xTCP.xTCPWindow.rx.ulTimeStamp = ulChar2u32( pucPtr ); - pxSocket->u.xTCP.xTCPWindow.tx.ulTimeStamp = ulChar2u32( pucPtr + 4 ); - } - #endif /* ipconfigUSE_TCP_TIMESTAMPS == 1 */ } #endif /* ipconfigUSE_TCP_WIN == 1 */ @@ -1371,24 +1388,13 @@ UBaseType_t uxOptionsLength; } #else { - #if( ipconfigUSE_TCP_TIMESTAMPS == 1 ) - if( pxSocket->u.xTCP.xTCPWindow.u.bits.bTimeStamps ) - { - uxOptionsLength += prvTCPSetTimeStamp( uxOptionsLength, pxSocket, &pxTCPPacket->xTCPHeader ); - pxTCPHeader->ucOptdata[ uxOptionsLength + 0 ] = TCP_OPT_SACK_P; /* 4: Sack-Permitted Option. */ - pxTCPHeader->ucOptdata[ uxOptionsLength + 1 ] = 2u; - uxOptionsLength += 2u; - } - else - #endif - { - pxTCPHeader->ucOptdata[ uxOptionsLength + 0 ] = TCP_OPT_NOOP; - pxTCPHeader->ucOptdata[ uxOptionsLength + 1 ] = TCP_OPT_NOOP; - pxTCPHeader->ucOptdata[ uxOptionsLength + 2 ] = TCP_OPT_SACK_P; /* 4: Sack-Permitted Option. */ - pxTCPHeader->ucOptdata[ uxOptionsLength + 3 ] = 2; /* 2: length of this option. */ - uxOptionsLength += 4u; - } - return uxOptionsLength; /* bytes, not words. */ + pxTCPHeader->ucOptdata[ uxOptionsLength + 0 ] = TCP_OPT_NOOP; + pxTCPHeader->ucOptdata[ uxOptionsLength + 1 ] = TCP_OPT_NOOP; + pxTCPHeader->ucOptdata[ uxOptionsLength + 2 ] = TCP_OPT_SACK_P; /* 4: Sack-Permitted Option. */ + pxTCPHeader->ucOptdata[ uxOptionsLength + 3 ] = 2; /* 2: length of this option. */ + uxOptionsLength += 4u; + + return uxOptionsLength; /* bytes, not words. */ } #endif /* ipconfigUSE_TCP_WIN == 0 */ } @@ -1566,7 +1572,7 @@ BaseType_t bAfter = ( BaseType_t ) NOW_CONNECTED( eTCPState ); /* Is it co /* Fill in the new state. */ pxSocket->u.xTCP.ucTCPState = ( uint8_t ) eTCPState; - /* Touch the alive timers because moving to another state. */ + /* touch the alive timers because moving to another state. */ prvTCPTouchSocket( pxSocket ); #if( ipconfigHAS_DEBUG_PRINTF == 1 ) @@ -1621,14 +1627,7 @@ BaseType_t xResize; ( int32_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength ) + lDataLen ); /* In case we were called from a TCP timer event, a buffer must be created. Otherwise, test 'xDataLength' of the provided buffer. */ - if( ( pxNetworkBuffer == NULL ) || ( pxNetworkBuffer->xDataLength < (size_t)lNeeded ) ) - { - xResize = pdTRUE; - } - else - { - xResize = pdFALSE; - } + xResize = ( pxNetworkBuffer == NULL ) || ( pxNetworkBuffer->xDataLength < (size_t)lNeeded ); } if( xResize != pdFALSE ) @@ -1640,6 +1639,9 @@ BaseType_t xResize; if( pxReturn != NULL ) { + /* Set the actual packet size, in case the returned buffer is larger. */ + pxReturn->xDataLength = lNeeded; + /* Copy the existing data to the new created buffer. */ if( pxNetworkBuffer ) { @@ -1695,8 +1697,8 @@ int32_t lStreamPos; pucEthernetBuffer = pxSocket->u.xTCP.xPacket.u.ucLastPacket; } - pxTCPPacket = ( TCPPacket_t * ) pucEthernetBuffer; - pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow ); + pxTCPPacket = ( TCPPacket_t * ) ( pucEthernetBuffer ); + pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow; lDataLen = 0; lStreamPos = 0; pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_FLAG_ACK; @@ -1848,19 +1850,6 @@ int32_t lStreamPos; pxTCPPacket->xTCPHeader.ucTCPFlags |= ( uint8_t ) ipTCP_FLAG_PSH; } - #if ipconfigUSE_TCP_TIMESTAMPS == 1 - { - if( uxOptionsLength == 0u ) - { - if( pxSocket->u.xTCP.xTCPWindow.u.bits.bTimeStamps ) - { - TCPPacket_t * pxTCPPacket = ( TCPPacket_t * ) ( pucEthernetBuffer ); - uxOptionsLength = prvTCPSetTimeStamp( 0, pxSocket, &pxTCPPacket->xTCPHeader ); - } - } - } - #endif - lDataLen += ( int32_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength ); } @@ -1941,9 +1930,9 @@ int32_t lCount, lLength; /* A txStream has been created already, see if the socket has new data for the sliding window. - uxStreamBufferMidSpace() returns the distance between rxHead and rxMid. It - contains new Tx data which has not been passed to the sliding window yet. - The oldest data not-yet-confirmed can be found at rxTail. */ + uxStreamBufferMidSpace() returns the distance between rxHead and rxMid. It contains new + Tx data which has not been passed to the sliding window yet. The oldest + data not-yet-confirmed can be found at rxTail. */ lLength = ( int32_t ) uxStreamBufferMidSpace( pxSocket->u.xTCP.txStream ); if( lLength > 0 ) @@ -2064,29 +2053,6 @@ uint32_t ulAckNr = FreeRTOS_ntohl( pxTCPHeader->ulAckNr ); } /*-----------------------------------------------------------*/ -#if ipconfigUSE_TCP_TIMESTAMPS == 1 - - static UBaseType_t prvTCPSetTimeStamp( BaseType_t lOffset, FreeRTOS_Socket_t *pxSocket, TCPHeader_t *pxTCPHeader ) - { - uint32_t ulTimes[2]; - uint8_t *ucOptdata = &( pxTCPHeader->ucOptdata[ lOffset ] ); - - ulTimes[0] = ( xTaskGetTickCount ( ) * 1000u ) / configTICK_RATE_HZ; - ulTimes[0] = FreeRTOS_htonl( ulTimes[0] ); - ulTimes[1] = FreeRTOS_htonl( pxSocket->u.xTCP.xTCPWindow.rx.ulTimeStamp ); - ucOptdata[0] = ( uint8_t ) TCP_OPT_TIMESTAMP; - ucOptdata[1] = ( uint8_t ) TCP_OPT_TIMESTAMP_LEN; - memcpy( &(ucOptdata[2] ), ulTimes, 8u ); - ucOptdata[10] = ( uint8_t ) TCP_OPT_NOOP; - ucOptdata[11] = ( uint8_t ) TCP_OPT_NOOP; - /* Do not return the same timestamps 2 times. */ - pxSocket->u.xTCP.xTCPWindow.rx.ulTimeStamp = 0ul; - return 12u; - } - -#endif -/*-----------------------------------------------------------*/ - /* * prvCheckRxData(): called from prvTCPHandleState() * @@ -2279,15 +2245,6 @@ UBaseType_t uxOptionsLength = pxTCPWindow->ucOptionLength; pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 ); } - #if( ipconfigUSE_TCP_TIMESTAMPS == 1 ) - { - if( pxSocket->u.xTCP.xTCPWindow.u.bits.bTimeStamps ) - { - uxOptionsLength += prvTCPSetTimeStamp( uxOptionsLength, pxSocket, pxTCPHeader ); - } - } - #endif /* ipconfigUSE_TCP_TIMESTAMPS == 1 */ - return uxOptionsLength; } /*-----------------------------------------------------------*/ @@ -2941,16 +2898,31 @@ BaseType_t xProcessReceivedTCPPacket( NetworkBufferDescriptor_t *pxNetworkBuffer { FreeRTOS_Socket_t *pxSocket; TCPPacket_t * pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer ); -uint16_t ucTCPFlags = pxTCPPacket->xTCPHeader.ucTCPFlags; -uint32_t ulLocalIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulDestinationIPAddress ); -uint16_t xLocalPort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usDestinationPort ); -uint32_t ulRemoteIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulSourceIPAddress ); -uint16_t xRemotePort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usSourcePort ); +uint16_t ucTCPFlags; +uint32_t ulLocalIP; +uint16_t xLocalPort; +uint32_t ulRemoteIP; +uint16_t xRemotePort; BaseType_t xResult = pdPASS; - /* Find the destination socket, and if not found: return a socket listing to - the destination PORT. */ - pxSocket = ( FreeRTOS_Socket_t * ) pxTCPSocketLookup( ulLocalIP, xLocalPort, ulRemoteIP, xRemotePort ); + /* Check for a minimum packet size. */ + if( pxNetworkBuffer->xDataLength >= + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) + { + ucTCPFlags = pxTCPPacket->xTCPHeader.ucTCPFlags; + ulLocalIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulDestinationIPAddress ); + xLocalPort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usDestinationPort ); + ulRemoteIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulSourceIPAddress ); + xRemotePort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usSourcePort ); + + /* Find the destination socket, and if not found: return a socket listing to + the destination PORT. */ + pxSocket = ( FreeRTOS_Socket_t * )pxTCPSocketLookup( ulLocalIP, xLocalPort, ulRemoteIP, xRemotePort ); + } + else + { + return pdFAIL; + } if( ( pxSocket == NULL ) || ( prvTCPSocketIsActive( ( UBaseType_t ) pxSocket->u.xTCP.ucTCPState ) == pdFALSE ) ) { @@ -3111,59 +3083,71 @@ BaseType_t xResult = pdPASS; static FreeRTOS_Socket_t *prvHandleListen( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer ) { TCPPacket_t * pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer ); -FreeRTOS_Socket_t *pxReturn; +FreeRTOS_Socket_t *pxReturn = NULL; +uint32_t ulInitialSequenceNumber; + + /* Assume that a new Initial Sequence Number will be required. Request + it now in order to fail out if necessary. */ + ulInitialSequenceNumber = ulApplicationGetNextSequenceNumber( + *ipLOCAL_IP_ADDRESS_POINTER, + pxSocket->usLocalPort, + pxTCPPacket->xIPHeader.ulSourceIPAddress, + pxTCPPacket->xTCPHeader.usSourcePort ); /* A pure SYN (without ACK) has come in, create a new socket to answer it. */ - if( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED ) - { - /* The flag bReuseSocket indicates that the same instance of the - listening socket should be used for the connection. */ - pxReturn = pxSocket; - pxSocket->u.xTCP.bits.bPassQueued = pdTRUE_UNSIGNED; - pxSocket->u.xTCP.pxPeerSocket = pxSocket; - } - else - { - /* The socket does not have the bReuseSocket flag set meaning create a - new socket when a connection comes in. */ - pxReturn = NULL; - - if( pxSocket->u.xTCP.usChildCount >= pxSocket->u.xTCP.usBacklog ) - { - FreeRTOS_printf( ( "Check: Socket %u already has %u / %u child%s\n", - pxSocket->usLocalPort, - pxSocket->u.xTCP.usChildCount, - pxSocket->u.xTCP.usBacklog, - pxSocket->u.xTCP.usChildCount == 1 ? "" : "ren" ) ); - prvTCPSendReset( pxNetworkBuffer ); - } - else - { - FreeRTOS_Socket_t *pxNewSocket = (FreeRTOS_Socket_t *) - FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP ); - - if( ( pxNewSocket == NULL ) || ( pxNewSocket == FREERTOS_INVALID_SOCKET ) ) - { - FreeRTOS_debug_printf( ( "TCP: Listen: new socket failed\n" ) ); - prvTCPSendReset( pxNetworkBuffer ); - } - else if( prvTCPSocketCopy( pxNewSocket, pxSocket ) != pdFALSE ) - { - /* The socket will be connected immediately, no time for the - owner to setsockopt's, therefore copy properties of the server - socket to the new socket. Only the binding might fail (due to - lack of resources). */ - pxReturn = pxNewSocket; - } - } - } - - if( pxReturn != NULL ) + if( 0 != ulInitialSequenceNumber ) + { + if( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED ) + { + /* The flag bReuseSocket indicates that the same instance of the + listening socket should be used for the connection. */ + pxReturn = pxSocket; + pxSocket->u.xTCP.bits.bPassQueued = pdTRUE_UNSIGNED; + pxSocket->u.xTCP.pxPeerSocket = pxSocket; + } + else + { + /* The socket does not have the bReuseSocket flag set meaning create a + new socket when a connection comes in. */ + pxReturn = NULL; + + if( pxSocket->u.xTCP.usChildCount >= pxSocket->u.xTCP.usBacklog ) + { + FreeRTOS_printf( ( "Check: Socket %u already has %u / %u child%s\n", + pxSocket->usLocalPort, + pxSocket->u.xTCP.usChildCount, + pxSocket->u.xTCP.usBacklog, + pxSocket->u.xTCP.usChildCount == 1 ? "" : "ren" ) ); + prvTCPSendReset( pxNetworkBuffer ); + } + else + { + FreeRTOS_Socket_t *pxNewSocket = ( FreeRTOS_Socket_t * ) + FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP ); + + if( ( pxNewSocket == NULL ) || ( pxNewSocket == FREERTOS_INVALID_SOCKET ) ) + { + FreeRTOS_debug_printf( ( "TCP: Listen: new socket failed\n" ) ); + prvTCPSendReset( pxNetworkBuffer ); + } + else if( prvTCPSocketCopy( pxNewSocket, pxSocket ) != pdFALSE ) + { + /* The socket will be connected immediately, no time for the + owner to setsockopt's, therefore copy properties of the server + socket to the new socket. Only the binding might fail (due to + lack of resources). */ + pxReturn = pxNewSocket; + } + } + } + } + + if( 0 != ulInitialSequenceNumber && pxReturn != NULL ) { pxReturn->u.xTCP.usRemotePort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usSourcePort ); pxReturn->u.xTCP.ulRemoteIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulSourceIPAddress ); - pxReturn->u.xTCP.xTCPWindow.ulOurSequenceNumber = ulNextInitialSequenceNumber; + pxReturn->u.xTCP.xTCPWindow.ulOurSequenceNumber = ulInitialSequenceNumber; /* Here is the SYN action. */ pxReturn->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber = FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulSequenceNumber ); @@ -3171,9 +3155,6 @@ FreeRTOS_Socket_t *pxReturn; prvTCPCreateWindow( pxReturn ); - /* It is recommended to increase the ISS for each new connection with a value of 0x102. */ - ulNextInitialSequenceNumber += INITIAL_SEQUENCE_NUMBER_INCREMENT; - vTCPStateChange( pxReturn, eSYN_FIRST ); /* Make a copy of the header up to the TCP header. It is needed later @@ -3248,7 +3229,7 @@ struct freertos_sockaddr xAddress; /* A reference to the new socket may be stored and the socket is marked as 'passable'. */ - /* When bPassAccept is true, this socket may be returned in a call to + /* When bPassAccept is pdTRUE_UNSIGNED this socket may be returned in a call to accept(). */ pxNewSocket->u.xTCP.bits.bPassAccept = pdTRUE_UNSIGNED; if(pxSocket->u.xTCP.pxPeerSocket == NULL ) @@ -3327,3 +3308,7 @@ BaseType_t xResult = pdFALSE; #endif /* ipconfigUSE_TCP == 1 */ +/* Provide access to private members for testing. */ +#ifdef AMAZON_FREERTOS_ENABLE_UNIT_TESTS + #include "aws_freertos_tcp_test_access_tcp_define.h" +#endif diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_WIN.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_WIN.c index 556482a82..11dc00f01 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_WIN.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_WIN.c @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.3 + * FreeRTOS+TCP V2.0.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 @@ -199,7 +199,7 @@ extern void vListInsertGeneric( List_t * const pxList, ListItem_t * const pxNewL /*-----------------------------------------------------------*/ -/* TCP segment pool. */ +/* TCP segement pool. */ #if( ipconfigUSE_TCP_WIN == 1 ) static TCPSegment_t *xTCPSegments = NULL; #endif /* ipconfigUSE_TCP_WIN == 1 */ @@ -292,7 +292,7 @@ void vListInsertGeneric( List_t * const pxList, ListItem_t * const pxNewListItem pxWhere->pxPrevious = pxNewListItem; /* Remember which list the item is in. */ - pxNewListItem->pxContainer = pxList; + pxNewListItem->pvContainer = ( void * ) pxList; /* If this line fails to build then ensure configENABLE_BACKWARD_COMPATIBILITY is set to 1 in FreeRTOSConfig.h. */ ( pxList->uxNumberOfItems )++; } @@ -597,12 +597,12 @@ void vTCPWindowCreate( TCPWindow_t *pxWindow, uint32_t ulRxWindowLength, prvCreateSectors(); } - vListInitialise( &( pxWindow->xTxSegments ) ); - vListInitialise( &( pxWindow->xRxSegments ) ); + vListInitialise( &pxWindow->xTxSegments ); + vListInitialise( &pxWindow->xRxSegments ); - vListInitialise( &( pxWindow->xPriorityQueue ) ); /* Priority queue: segments which must be sent immediately */ - vListInitialise( &( pxWindow->xTxQueue ) ); /* Transmit queue: segments queued for transmission */ - vListInitialise( &( pxWindow->xWaitQueue ) ); /* Waiting queue: outstanding segments */ + vListInitialise( &pxWindow->xPriorityQueue ); /* Priority queue: segments which must be sent immediately */ + vListInitialise( &pxWindow->xTxQueue ); /* Transmit queue: segments queued for transmission */ + vListInitialise( &pxWindow->xWaitQueue ); /* Waiting queue: outstanding segments */ } #endif /* ipconfigUSE_TCP_WIN == 1 */ @@ -788,23 +788,20 @@ const int32_t l500ms = 500; { ulSavedSequenceNumber = ulCurrentSequenceNumber; - /* Clean up all sequence received between ulSequenceNumber - and ulSequenceNumber + ulLength since they are duplicated. - If the server is forced to retransmit packets several time - in a row it might send a batch of concatenated packet for - speed. So we cannot rely on the packets between - ulSequenceNumber and ulSequenceNumber + ulLength to be - sequential and it is better to just clean them out. */ - do - { - pxFound = xTCPWindowRxConfirm( pxWindow, ulSequenceNumber, ulLength ); - - if ( pxFound != NULL ) - { - /* Remove it because it will be passed to user directly. */ - vTCPWindowFree( pxFound ); - } - } while ( pxFound ); + /* Clean up all sequence received between ulSequenceNumber and ulSequenceNumber + ulLength since they are duplicated. + If the server is forced to retransmit packets several time in a row it might send a batch of concatenated packet for speed. + So we cannot rely on the packets between ulSequenceNumber and ulSequenceNumber + ulLength to be sequential and it is better to just + clean them out. */ + do + { + pxFound = xTCPWindowRxConfirm( pxWindow, ulSequenceNumber, ulLength ); + + if ( pxFound != NULL ) + { + /* Remove it because it will be passed to user directly. */ + vTCPWindowFree( pxFound ); + } + } while ( pxFound ); /* Check for following segments that are already in the queue and increment ulCurrentSequenceNumber. */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_UDP_IP.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_UDP_IP.c index 8262a5104..94a8e17f8 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_UDP_IP.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_UDP_IP.c @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.3 + * FreeRTOS+TCP V2.0.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 @@ -128,15 +128,16 @@ uint32_t ulIPAddress = pxNetworkBuffer->ulIPAddress; and xIPHeader.usHeaderChecksum */ - /* Save options now, as they will be overwritten by memcpy */ #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 ) - { ucSocketOptions = pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ]; - } #endif - - memcpy( ( void *) &( pxUDPPacket->xEthernetHeader.xSourceAddress ), ( void * ) xDefaultPartUDPPacketHeader.ucBytes, sizeof( xDefaultPartUDPPacketHeader ) ); + /* + * Offset the memcpy by the size of a MAC address to start at the packet's + * Ethernet header 'source' MAC address; the preceding 'destination' should not be altered. + */ + char *pxUdpSrcAddrOffset = ( char *) pxUDPPacket + sizeof( MACAddress_t ); + memcpy( pxUdpSrcAddrOffset, xDefaultPartUDPPacketHeader.ucBytes, sizeof( xDefaultPartUDPPacketHeader ) ); #if ipconfigSUPPORT_OUTGOING_PINGS == 1 if( pxNetworkBuffer->usPort == ipPACKET_CONTAINS_ICMP_DATA ) @@ -153,6 +154,7 @@ uint32_t ulIPAddress = pxNetworkBuffer->ulIPAddress; /* The total transmit size adds on the Ethernet header. */ pxNetworkBuffer->xDataLength = pxIPHeader->usLength + sizeof( EthernetHeader_t ); pxIPHeader->usLength = FreeRTOS_htons( pxIPHeader->usLength ); + /* HT:endian: changed back to network endian */ pxIPHeader->ulDestinationIPAddress = pxNetworkBuffer->ulIPAddress; #if( ipconfigUSE_LLMNR == 1 ) @@ -174,7 +176,7 @@ uint32_t ulIPAddress = pxNetworkBuffer->ulIPAddress; if( ( ucSocketOptions & ( uint8_t ) FREERTOS_SO_UDPCKSUM_OUT ) != 0u ) { - usGenerateProtocolChecksum( (uint8_t*)pxUDPPacket, pdTRUE ); + usGenerateProtocolChecksum( (uint8_t*)pxUDPPacket, pxNetworkBuffer->xDataLength, pdTRUE ); } else { @@ -241,7 +243,8 @@ FreeRTOS_Socket_t *pxSocket; UDPPacket_t *pxUDPPacket = (UDPPacket_t *) pxNetworkBuffer->pucEthernetBuffer; - pxSocket = pxUDPSocketLookup( usPort ); + /* Caller must check for minimum packet size. */ + pxSocket = pxUDPSocketLookup( usPort ); if( pxSocket ) { @@ -265,9 +268,9 @@ UDPPacket_t *pxUDPPacket = (UDPPacket_t *) pxNetworkBuffer->pucEthernetBuffer; destinationAddress.sin_addr = pxUDPPacket->xIPHeader.ulDestinationIPAddress; if( xHandler( ( Socket_t * ) pxSocket, ( void* ) pcData, ( size_t ) pxNetworkBuffer->xDataLength, - &xSourceAddress, &destinationAddress ) != pdFALSE ) + &xSourceAddress, &destinationAddress ) ) { - xReturn = pdFAIL; /* xHandler has consumed the data, do not add it to .xWaitingPacketsList'. */ + xReturn = pdFAIL; /* FAIL means that we did not consume or release the buffer */ } } } @@ -344,21 +347,8 @@ UDPPacket_t *pxUDPPacket = (UDPPacket_t *) pxNetworkBuffer->pucEthernetBuffer; /* There is no socket listening to the target port, but still it might be for this node. */ - #if( ipconfigUSE_DNS == 1 ) - /* A DNS reply, check for the source port. Although the DNS client - does open a UDP socket to send a messages, this socket will be - closed after a short timeout. Messages that come late (after the - socket is closed) will be treated here. */ - if( FreeRTOS_ntohs( pxUDPPacket->xUDPHeader.usSourcePort ) == ipDNS_PORT ) - { - vARPRefreshCacheEntry( &( pxUDPPacket->xEthernetHeader.xSourceAddress ), pxUDPPacket->xIPHeader.ulSourceIPAddress ); - xReturn = ( BaseType_t )ulDNSHandlePacket( pxNetworkBuffer ); - } - else - #endif - #if( ipconfigUSE_LLMNR == 1 ) - /* An LLMNR request, check for the destination port. */ + /* a LLMNR request, check for the destination port. */ if( ( usPort == FreeRTOS_ntohs( ipLLMNR_PORT ) ) || ( pxUDPPacket->xUDPHeader.usSourcePort == FreeRTOS_ntohs( ipLLMNR_PORT ) ) ) { diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/History.txt b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/History.txt index fd3ba86fa..b485a2833 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/History.txt +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/History.txt @@ -1,4 +1,11 @@ -Changes since V2.0.0 release +Changes between 160919 and 180821 releases: + + + Multiple security improvements and fixes in packet parsing routines, DNS + caching, and TCP sequence number and ID generation. + + Disable NBNS and LLMNR by default. + + Add TCP hang protection by default. + + We thank Ori Karliner of Zimperium zLabs Team for reporting these issues. + Update FreeRTOS_gethostbyname() to allow an IP address to be passed in - in which case it is just returned as a uint32_t. diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOSIPConfigDefaults.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOSIPConfigDefaults.h index 36781cca5..dd8ae07f4 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOSIPConfigDefaults.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOSIPConfigDefaults.h @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.3 + * FreeRTOS+TCP V2.0.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 @@ -389,11 +389,13 @@ from the FreeRTOSIPConfig.h configuration header file. */ #if( ipconfigUSE_DNS_CACHE != 0 ) #ifndef ipconfigDNS_CACHE_NAME_LENGTH - #define ipconfigDNS_CACHE_NAME_LENGTH ( 16 ) + /* Per https://tools.ietf.org/html/rfc1035, 253 is the maximum string length + of a DNS name. The following default accounts for a null terminator. */ + #define ipconfigDNS_CACHE_NAME_LENGTH 254 #endif #ifndef ipconfigDNS_CACHE_ENTRIES - #define ipconfigDNS_CACHE_ENTRIES 0 + #define ipconfigDNS_CACHE_ENTRIES 1 #endif #endif /* ipconfigUSE_DNS_CACHE != 0 */ @@ -510,7 +512,7 @@ from the FreeRTOSIPConfig.h configuration header file. */ #endif #ifndef ipconfigTCP_KEEP_ALIVE - #define ipconfigTCP_KEEP_ALIVE 1 + #define ipconfigTCP_KEEP_ALIVE 0 #endif #ifndef ipconfigDNS_USE_CALLBACKS @@ -525,10 +527,17 @@ from the FreeRTOSIPConfig.h configuration header file. */ #define ipconfigUSE_NBNS 0 #endif +/* As an attack surface reduction for ports that listen for inbound +connections, hang protection can help reduce the impact of SYN floods. */ #ifndef ipconfigTCP_HANG_PROTECTION #define ipconfigTCP_HANG_PROTECTION 1 #endif +/* Non-activity timeout is expressed in seconds. */ +#ifndef ipconfigTCP_HANG_PROTECTION_TIME + #define ipconfigTCP_HANG_PROTECTION_TIME 30 +#endif + #ifndef ipconfigTCP_IP_SANITY #define ipconfigTCP_IP_SANITY 0 #endif diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_ARP.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_ARP.h index 1eb700cc1..5f7e7871f 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_ARP.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_ARP.h @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.3 + * FreeRTOS+TCP V2.0.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 diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_DHCP.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_DHCP.h index 39c1b9239..3cdb4b6a8 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_DHCP.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_DHCP.h @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.3 + * FreeRTOS+TCP V2.0.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 diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_DNS.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_DNS.h index 10d35779d..9ab08873e 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_DNS.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_DNS.h @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.3 + * FreeRTOS+TCP V2.0.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 diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_IP.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_IP.h index 6fd33585f..11342aeeb 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_IP.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_IP.h @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.3 + * FreeRTOS+TCP V2.0.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 diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_IP_Private.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_IP_Private.h index 518c20e92..254201d19 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_IP_Private.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_IP_Private.h @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.3 + * FreeRTOS+TCP V2.0.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 @@ -436,8 +436,18 @@ eFrameProcessingResult_t eConsiderFrameForProcessing( const uint8_t * const pucE uint16_t usGenerateChecksum( uint32_t ulSum, const uint8_t * pucNextData, size_t uxDataLengthBytes ); /* Socket related private functions. */ + +/* + * The caller must ensure that pxNetworkBuffer->xDataLength is the UDP packet + * payload size (excluding packet headers) and that the packet in pucEthernetBuffer + * is at least the size of UDPPacket_t. + */ BaseType_t xProcessReceivedUDPPacket( NetworkBufferDescriptor_t *pxNetworkBuffer, uint16_t usPort ); -void vNetworkSocketsInit( void ); + +/* + * Initialize the socket list data structures for TCP and UDP. + */ +BaseType_t vNetworkSocketsInit( void ); /* * Returns pdTRUE if the IP task has been created and is initialised. Otherwise @@ -671,7 +681,7 @@ void vProcessGeneratedUDPPacket( NetworkBufferDescriptor_t * const pxNetworkBuff * bOut = false: checksum will be calculated for incoming packets * returning 0xffff means: checksum was correct */ -uint16_t usGenerateProtocolChecksum( const uint8_t * const pucEthernetBuffer, BaseType_t xOutgoingPacket ); +uint16_t usGenerateProtocolChecksum( const uint8_t * const pucEthernetBuffer, size_t uxBufferLength, BaseType_t xOutgoingPacket ); /* * An Ethernet frame has been updated (maybe it was an ARP request or a PING diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_Sockets.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_Sockets.h index c51ad5aee..a8a5710b7 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_Sockets.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_Sockets.h @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.3 + * FreeRTOS+TCP V2.0.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 diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_Stream_Buffer.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_Stream_Buffer.h index bbdc55e0f..1d088e716 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_Stream_Buffer.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_Stream_Buffer.h @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.3 + * FreeRTOS+TCP V2.0.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 diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_TCP_IP.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_TCP_IP.h index 26e729b9e..4a7aa00f9 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_TCP_IP.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_TCP_IP.h @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.3 + * FreeRTOS+TCP V2.0.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 diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_TCP_WIN.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_TCP_WIN.h index 7f7f6c0df..74bb71ebc 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_TCP_WIN.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_TCP_WIN.h @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.3 + * FreeRTOS+TCP V2.0.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 @@ -80,17 +80,9 @@ typedef struct xTCP_WINSIZE */ /* Keep this as a multiple of 4 */ #if( ipconfigUSE_TCP_WIN == 1 ) - #if( ipconfigUSE_TCP_TIMESTAMPS == 1 ) - #define ipSIZE_TCP_OPTIONS ( 16u + 12u ) - #else - #define ipSIZE_TCP_OPTIONS 16u - #endif + #define ipSIZE_TCP_OPTIONS 16u #else - #if ipconfigUSE_TCP_TIMESTAMPS == 1 - #define ipSIZE_TCP_OPTIONS ( 12u + 12u ) - #else - #define ipSIZE_TCP_OPTIONS 12u - #endif + #define ipSIZE_TCP_OPTIONS 12u #endif /* @@ -120,9 +112,6 @@ typedef struct xTCP_WINDOW * In other words: the sequence number of the left side of the sliding window */ uint32_t ulFINSequenceNumber; /* The sequence number which carried the FIN flag */ uint32_t ulHighestSequenceNumber;/* Sequence number of the right-most byte + 1 */ -#if( ipconfigUSE_TCP_TIMESTAMPS == 1 ) - uint32_t ulTimeStamp; /* The value of the TCP timestamp, transmitted or received */ -#endif } rx, tx; uint32_t ulOurSequenceNumber; /* The SEQ number we're sending out */ uint32_t ulUserDataLength; /* Number of bytes in Rx buffer which may be passed to the user, after having received a 'missing packet' */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_UDP_IP.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_UDP_IP.h index 1b0dc55c5..ca70b3abd 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_UDP_IP.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_UDP_IP.h @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.3 + * FreeRTOS+TCP V2.0.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 diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_errno_TCP.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_errno_TCP.h index 8a92b289b..bb405eaf9 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_errno_TCP.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_errno_TCP.h @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.3 + * FreeRTOS+TCP V2.0.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 diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/IPTraceMacroDefaults.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/IPTraceMacroDefaults.h index a8818207e..6f1f5e360 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/IPTraceMacroDefaults.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/IPTraceMacroDefaults.h @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.3 + * FreeRTOS+TCP V2.0.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 diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/NetworkBufferManagement.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/NetworkBufferManagement.h index f2397e359..e05f0ac8f 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/NetworkBufferManagement.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/NetworkBufferManagement.h @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.3 + * FreeRTOS+TCP V2.0.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 diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/NetworkInterface.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/NetworkInterface.h index 58118465d..f5f246503 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/NetworkInterface.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include/NetworkInterface.h @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.3 + * FreeRTOS+TCP V2.0.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 diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/BufferManagement/BufferAllocation_1.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/BufferManagement/BufferAllocation_1.c index 6ac78afad..f8b04e420 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/BufferManagement/BufferAllocation_1.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/BufferManagement/BufferAllocation_1.c @@ -1,28 +1,27 @@ /* - * FreeRTOS+TCP V2.0.3 - * 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+TCP V2.0.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 +*/ /****************************************************************************** * @@ -226,7 +225,7 @@ UBaseType_t uxCount; available. */ if( xSemaphoreTake( xNetworkBufferSemaphore, xBlockTimeTicks ) == pdPASS ) { - /* Protect the structure as it is accessed from tasks and + /* Protect the structure as they are accessed from tasks and interrupts. */ ipconfigBUFFER_ALLOC_LOCK(); { diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/BufferManagement/BufferAllocation_2.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/BufferManagement/BufferAllocation_2.c index 467e5b86b..e158e39bb 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/BufferManagement/BufferAllocation_2.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/BufferManagement/BufferAllocation_2.c @@ -1,5 +1,5 @@ /* - * FreeRTOS+TCP V2.0.3 + * FreeRTOS+TCP V2.0.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 @@ -19,11 +19,12 @@ * 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 + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! */ - /****************************************************************************** * * See the following web page for essential buffer allocation scheme usage and @@ -323,12 +324,21 @@ BaseType_t xListItemAlreadyInFreeList; } taskEXIT_CRITICAL(); + /* + * Update the network state machine, unless the program fails to release its 'xNetworkBufferSemaphore'. + * The program should only try to release its semaphore if 'xListItemAlreadyInFreeList' is false. + */ if( xListItemAlreadyInFreeList == pdFALSE ) { - xSemaphoreGive( xNetworkBufferSemaphore ); + if ( xSemaphoreGive( xNetworkBufferSemaphore ) == pdTRUE ) + { + iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer ); + } + } + else + { + iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer ); } - - iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer ); } /*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/GCC/pack_struct_end.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/GCC/pack_struct_end.h index a122660d7..606f7df15 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/GCC/pack_struct_end.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/GCC/pack_struct_end.h @@ -1,28 +1,27 @@ /* - * FreeRTOS+TCP V2.0.3 - * 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+TCP V2.0.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 +*/ /***************************************************************************** * diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/GCC/pack_struct_start.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/GCC/pack_struct_start.h index 34926c288..8893ec01f 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/GCC/pack_struct_start.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/GCC/pack_struct_start.h @@ -1,28 +1,27 @@ /* - * FreeRTOS+TCP V2.0.3 - * 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+TCP V2.0.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 +*/ /***************************************************************************** * diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/IAR/pack_struct_end.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/IAR/pack_struct_end.h index 185de8b35..104ecef17 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/IAR/pack_struct_end.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/IAR/pack_struct_end.h @@ -1,28 +1,27 @@ /* - * FreeRTOS+TCP V2.0.3 - * 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+TCP V2.0.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 +*/ /***************************************************************************** * diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/IAR/pack_struct_start.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/IAR/pack_struct_start.h index 2be3bcac8..f012d9988 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/IAR/pack_struct_start.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/IAR/pack_struct_start.h @@ -1,28 +1,27 @@ /* - * FreeRTOS+TCP V2.0.3 - * 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+TCP V2.0.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 +*/ /***************************************************************************** * diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/MSVC/pack_struct_end.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/MSVC/pack_struct_end.h index 4ab7f753b..54dffdde5 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/MSVC/pack_struct_end.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/MSVC/pack_struct_end.h @@ -1,28 +1,27 @@ /* - * FreeRTOS+TCP V2.0.3 - * 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+TCP V2.0.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 +*/ /***************************************************************************** * diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/MSVC/pack_struct_start.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/MSVC/pack_struct_start.h index 5ef2b5d14..f133207cb 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/MSVC/pack_struct_start.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/MSVC/pack_struct_start.h @@ -1,28 +1,27 @@ /* - * FreeRTOS+TCP V2.0.3 - * 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+TCP V2.0.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 +*/ /***************************************************************************** * diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/Renesas/pack_struct_end.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/Renesas/pack_struct_end.h index afe5be971..b49313602 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/Renesas/pack_struct_end.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/Renesas/pack_struct_end.h @@ -1,28 +1,27 @@ /* - * FreeRTOS+TCP V2.0.3 - * 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+TCP V2.0.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 +*/ /***************************************************************************** * diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/Renesas/pack_struct_start.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/Renesas/pack_struct_start.h index d1ae7f94d..9436de7de 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/Renesas/pack_struct_start.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/Renesas/pack_struct_start.h @@ -1,28 +1,27 @@ /* - * FreeRTOS+TCP V2.0.3 - * 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+TCP V2.0.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 +*/ /***************************************************************************** * diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC17xx/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC17xx/NetworkInterface.c index d96ff29c6..7799731b4 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC17xx/NetworkInterface.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC17xx/NetworkInterface.c @@ -1,28 +1,27 @@ /* - * FreeRTOS+TCP V2.0.3 - * 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+TCP V2.0.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 +*/ /* Standard includes. */ #include diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/SH2A/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/SH2A/NetworkInterface.c index cb554f426..de077131f 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/SH2A/NetworkInterface.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/SH2A/NetworkInterface.c @@ -1,28 +1,27 @@ /* - * FreeRTOS+TCP V2.0.3 - * 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+TCP V2.0.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 +*/ /* Standard includes. */ #include diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/NetworkInterface.c index 4e13ee3f0..268273cd9 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/NetworkInterface.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/NetworkInterface.c @@ -787,16 +787,11 @@ uint8_t *pucBuffer; } /* Obtain the size of the packet and put it into the "usReceivedLength" variable. */ - - /* get received frame */ - if( xReceivedLength > 0ul ) + /* In order to make the code easier and faster, only packets in a single buffer + will be accepted. This can be done by making the buffers large enough to + hold a complete Ethernet packet (1536 bytes). */ + if( xReceivedLength > 0ul && xReceivedLength < ETH_RX_BUF_SIZE ) { - /* In order to make the code easier and faster, only packets in a single buffer - will be accepted. This can be done by making the buffers large enough to - hold a complete Ethernet packet (1536 bytes). - Therefore, two sanity checks: */ - configASSERT( xReceivedLength <= ETH_RX_BUF_SIZE ); - if( ( pxDMARxDescriptor->Status & ( ETH_DMARXDESC_CE | ETH_DMARXDESC_IPV4HCE | ETH_DMARXDESC_FT ) ) != ETH_DMARXDESC_FT ) { /* Not an Ethernet frame-type or a checmsum error. */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/WinPCap/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/WinPCap/NetworkInterface.c index cca53970e..86579ecdb 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/WinPCap/NetworkInterface.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/WinPCap/NetworkInterface.c @@ -1,28 +1,27 @@ /* - * FreeRTOS+TCP V2.0.3 - * 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+TCP V2.0.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 +*/ /* WinPCap includes. */ #define HAVE_REMOTE @@ -80,7 +79,7 @@ static pcap_if_t * prvPrintAvailableNetworkInterfaces( void ); * by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h. */ static void prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces ); -static void prvOpenInterface( const char *pucName ); +static int prvOpenInterface( const char *pucName ); /* * Configure the capture filter to allow blocking reads, and to filter out @@ -275,7 +274,7 @@ static BaseType_t xInvalidInterfaceDetected = pdFALSE; printf( "\r\nThe interface that will be opened is set by " ); printf( "\"configNETWORK_INTERFACE_TO_USE\", which\r\nshould be defined in FreeRTOSConfig.h\r\n" ); - if( ( xConfigNextworkInterfaceToUse < 1L ) || ( xConfigNextworkInterfaceToUse >= lInterfaceNumber ) ) + if( ( xConfigNextworkInterfaceToUse < 0L ) || ( xConfigNextworkInterfaceToUse >= lInterfaceNumber ) ) { printf( "\r\nERROR: configNETWORK_INTERFACE_TO_USE is set to %d, which is an invalid value.\r\n", xConfigNextworkInterfaceToUse ); printf( "Please set configNETWORK_INTERFACE_TO_USE to one of the interface numbers listed above,\r\n" ); @@ -300,7 +299,7 @@ static BaseType_t xInvalidInterfaceDetected = pdFALSE; } /*-----------------------------------------------------------*/ -static void prvOpenInterface( const char *pucName ) +static int prvOpenInterface( const char *pucName ) { static char pucInterfaceName[ 256 ]; @@ -326,6 +325,7 @@ static char pucInterfaceName[ 256 ]; if ( pxOpenedInterfaceHandle == NULL ) { printf( "\n%s is not supported by WinPcap and cannot be opened\n", pucInterfaceName ); + return 1; } else { @@ -333,6 +333,7 @@ static char pucInterfaceName[ 256 ]; out packets that are not of interest to this demo. */ prvConfigureCaptureBehaviour(); } + return 0; } /*-----------------------------------------------------------*/ @@ -343,13 +344,22 @@ int32_t x; /* Walk the list of devices until the selected device is located. */ xInterface = pxAllNetworkInterfaces; - for( x = 0L; x < ( xConfigNextworkInterfaceToUse - 1L ); x++ ) - { - xInterface = xInterface->next; + if (0 == xConfigNextworkInterfaceToUse) { + while (NULL != xInterface) { + xInterface = xInterface->next; + if (0 == prvOpenInterface(xInterface->name)) { + break; + } + } + } + else { + for (x = 1L; x < xConfigNextworkInterfaceToUse; x++) + { + xInterface = xInterface->next; + } + /* Open the selected interface. */ + (void) prvOpenInterface(xInterface->name); } - - /* Open the selected interface. */ - prvOpenInterface( xInterface->name ); /* The device list is no longer required. */ pcap_freealldevs( pxAllNetworkInterfaces ); @@ -514,7 +524,16 @@ eFrameProcessingResult_t eResult; iptraceNETWORK_INTERFACE_RECEIVE(); - eResult = ipCONSIDER_FRAME_FOR_PROCESSING( pucPacketData ); + /* Check for minimal size. */ + if( pxHeader->len >= sizeof( EthernetHeader_t ) ) + { + eResult = ipCONSIDER_FRAME_FOR_PROCESSING( pucPacketData ); + } + else + { + eResult = eReleaseBuffer; + } + if( eResult == eProcessBuffer ) { /* Will the data fit into the frame buffer? */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/NetworkInterface.c index 92084617d..9d0b825a3 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/NetworkInterface.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/NetworkInterface.c @@ -1,28 +1,27 @@ /* - * FreeRTOS+TCP V2.0.3 - * 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+TCP V2.0.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 +*/ /* Standard includes. */ #include diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_dma.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_dma.c index 4c4bee560..b81841dcf 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_dma.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_dma.c @@ -1,27 +1,27 @@ /* - * FreeRTOS+TCP V2.0.3 - * 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+TCP V2.0.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 +*/ #include "Zynq/x_emacpsif.h" #include "Zynq/x_topology.h" diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ksz8851snl/NetworkInterface.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ksz8851snl/NetworkInterface.c index be18242a8..0b7e0dc23 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ksz8851snl/NetworkInterface.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ksz8851snl/NetworkInterface.c @@ -1,28 +1,27 @@ /* - * FreeRTOS+TCP V2.0.3 - * 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+TCP V2.0.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 +*/ /* Standard includes. */ #include diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/Common/FreeRTOS_TCP_server.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/Common/FreeRTOS_TCP_server.c deleted file mode 100644 index 3b9f8fb2f..000000000 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/Common/FreeRTOS_TCP_server.c +++ /dev/null @@ -1,353 +0,0 @@ -/* - * FreeRTOS+TCP V2.0.3 - * 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 - */ - - -/* Standard includes. */ -#include -#include -#include - -/* FreeRTOS includes. */ -#include "FreeRTOS.h" -#include "task.h" - -/* FreeRTOS+TCP includes. */ -#include "FreeRTOS_IP.h" -#include "FreeRTOS_Sockets.h" -#include "FreeRTOS_TCP_server.h" -#include "FreeRTOS_server_private.h" - -/* Remove the entire file if TCP is not being used. */ -#if( ipconfigUSE_TCP == 1 ) && ( ( ipconfigUSE_HTTP == 1 ) || ( ipconfigUSE_FTP == 1 ) ) - -#if !defined( ARRAY_SIZE ) - #define ARRAY_SIZE(x) ( BaseType_t ) (sizeof( x ) / sizeof( x )[ 0 ] ) -#endif - - -static void prvReceiveNewClient( TCPServer_t *pxServer, BaseType_t xIndex, Socket_t xNexSocket ); -static char *strnew( const char *pcString ); -/* Remove slashes at the end of a path. */ -static void prvRemoveSlash( char *pcDir ); - -TCPServer_t *FreeRTOS_CreateTCPServer( const struct xSERVER_CONFIG *pxConfigs, BaseType_t xCount ) -{ -TCPServer_t *pxServer; -SocketSet_t xSocketSet; - - /* Create a new server. - xPort / xPortAlt : Make the service available on 1 or 2 public port numbers. */ - xSocketSet = FreeRTOS_CreateSocketSet(); - - if( xSocketSet != NULL ) - { - BaseType_t xSize; - - xSize = sizeof( *pxServer ) - sizeof( pxServer->xServers ) + xCount * sizeof( pxServer->xServers[ 0 ] ); - - pxServer = ( TCPServer_t * ) pvPortMallocLarge( xSize ); - if( pxServer != NULL ) - { - struct freertos_sockaddr xAddress; - BaseType_t xNoTimeout = 0; - BaseType_t xIndex; - - memset( pxServer, '\0', xSize ); - pxServer->xServerCount = xCount; - pxServer->xSocketSet = xSocketSet; - - for( xIndex = 0; xIndex < xCount; xIndex++ ) - { - BaseType_t xPortNumber = pxConfigs[ xIndex ].xPortNumber; - - if( xPortNumber > 0 ) - { - Socket_t xSocket; - - xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP ); - FreeRTOS_printf( ( "TCP socket on port %d\n", ( int )xPortNumber ) ); - - if( xSocket != FREERTOS_NO_SOCKET ) - { - xAddress.sin_addr = FreeRTOS_GetIPAddress(); // Single NIC, currently not used - xAddress.sin_port = FreeRTOS_htons( xPortNumber ); - - FreeRTOS_bind( xSocket, &xAddress, sizeof( xAddress ) ); - FreeRTOS_listen( xSocket, pxConfigs[ xIndex ].xBackLog ); - - FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVTIMEO, ( void * ) &xNoTimeout, sizeof( BaseType_t ) ); - FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, ( void * ) &xNoTimeout, sizeof( BaseType_t ) ); - - #if( ipconfigHTTP_RX_BUFSIZE > 0 ) - { - if( pxConfigs[ xIndex ].eType == eSERVER_HTTP ) - { - WinProperties_t xWinProps; - - memset( &xWinProps, '\0', sizeof( xWinProps ) ); - /* The parent socket itself won't get connected. The properties below - will be inherited by each new child socket. */ - xWinProps.lTxBufSize = ipconfigHTTP_TX_BUFSIZE; - xWinProps.lTxWinSize = ipconfigHTTP_TX_WINSIZE; - xWinProps.lRxBufSize = ipconfigHTTP_RX_BUFSIZE; - xWinProps.lRxWinSize = ipconfigHTTP_RX_WINSIZE; - - /* Set the window and buffer sizes. */ - FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_WIN_PROPERTIES, ( void * ) &xWinProps, sizeof( xWinProps ) ); - } - } - #endif - - FreeRTOS_FD_SET( xSocket, xSocketSet, eSELECT_READ|eSELECT_EXCEPT ); - pxServer->xServers[ xIndex ].xSocket = xSocket; - pxServer->xServers[ xIndex ].eType = pxConfigs[ xIndex ].eType; - pxServer->xServers[ xIndex ].pcRootDir = strnew( pxConfigs[ xIndex ].pcRootDir ); - prvRemoveSlash( ( char * ) pxServer->xServers[ xIndex ].pcRootDir ); - } - } - } - } - else - { - /* Could not allocate the server, delete the socket set */ - FreeRTOS_DeleteSocketSet( xSocketSet ); - } - } - else - { - /* Could not create a socket set, return NULL */ - pxServer = NULL; - } - - return pxServer; -} -/*-----------------------------------------------------------*/ - -static void prvReceiveNewClient( TCPServer_t *pxServer, BaseType_t xIndex, Socket_t xNexSocket ) -{ -TCPClient_t *pxClient = NULL; -BaseType_t xSize = 0; -FTCPWorkFunction fWorkFunc = NULL; -FTCPDeleteFunction fDeleteFunc = NULL; -const char *pcType = "Unknown"; - - /*_RB_ Can the work and delete functions be part of the xSERVER_CONFIG structure - becomes generic, with no pre-processing required? */ - #if( ipconfigUSE_HTTP != 0 ) - { - if( pxServer->xServers[ xIndex ].eType == eSERVER_HTTP ) - { - xSize = sizeof( HTTPClient_t ); - fWorkFunc = xHTTPClientWork; - fDeleteFunc = vHTTPClientDelete; - pcType = "HTTP"; - } - } - #endif /* ipconfigUSE_HTTP != 0 */ - - #if( ipconfigUSE_FTP != 0 ) - { - if( pxServer->xServers[ xIndex ].eType == eSERVER_FTP ) - { - xSize = sizeof( FTPClient_t ); - fWorkFunc = xFTPClientWork; - fDeleteFunc = vFTPClientDelete; - pcType = "FTP"; - } - } - #endif /* ipconfigUSE_FTP != 0 */ - - /* Malloc enough space for a new HTTP-client */ - if( xSize ) - { - pxClient = ( TCPClient_t* ) pvPortMallocLarge( xSize ); - } - - if( pxClient != NULL ) - { - memset( pxClient, '\0', xSize ); - - /* Put the new client in front of the list. */ - pxClient->eType = pxServer->xServers[ xIndex ].eType; - pxClient->pcRootDir = pxServer->xServers[ xIndex ].pcRootDir; - pxClient->pxParent = pxServer; - pxClient->xSocket = xNexSocket; - pxClient->pxNextClient = pxServer->pxClients; - pxClient->fWorkFunction = fWorkFunc; - pxClient->fDeleteFunction = fDeleteFunc; - pxServer->pxClients = pxClient; - - FreeRTOS_FD_SET( xNexSocket, pxServer->xSocketSet, eSELECT_READ|eSELECT_EXCEPT ); - } - else - { - pcType = "closed"; - FreeRTOS_closesocket( xNexSocket ); - } - { - struct freertos_sockaddr xRemoteAddress; - FreeRTOS_GetRemoteAddress( pxClient->xSocket, &xRemoteAddress ); - FreeRTOS_printf( ( "TPC-server: new %s client %xip\n", pcType, (unsigned)FreeRTOS_ntohl( xRemoteAddress.sin_addr ) ) ); - } - - /* Remove compiler warnings in case FreeRTOS_printf() is not used. */ - ( void ) pcType; -} -/*-----------------------------------------------------------*/ - -void FreeRTOS_TCPServerWork( TCPServer_t *pxServer, TickType_t xBlockingTime ) -{ -TCPClient_t **ppxClient; -BaseType_t xIndex; -BaseType_t xRc; - - /* Let the server do one working cycle */ - xRc = FreeRTOS_select( pxServer->xSocketSet, xBlockingTime ); - - if( xRc != 0 ) - { - for( xIndex = 0; xIndex < pxServer->xServerCount; xIndex++ ) - { - struct freertos_sockaddr xAddress; - Socket_t xNexSocket; - socklen_t xSocketLength; - - if( pxServer->xServers[ xIndex ].xSocket == FREERTOS_NO_SOCKET ) - { - continue; - } - - xSocketLength = sizeof( xAddress ); - xNexSocket = FreeRTOS_accept( pxServer->xServers[ xIndex ].xSocket, &xAddress, &xSocketLength); - - if( ( xNexSocket != FREERTOS_NO_SOCKET ) && ( xNexSocket != FREERTOS_INVALID_SOCKET ) ) - { - prvReceiveNewClient( pxServer, xIndex, xNexSocket ); - } - } - } - - ppxClient = &pxServer->pxClients; - - while( ( * ppxClient ) != NULL ) - { - TCPClient_t *pxThis = *ppxClient; - - /* Almost C++ */ - xRc = pxThis->fWorkFunction( pxThis ); - - if (xRc < 0 ) - { - *ppxClient = pxThis->pxNextClient; - /* Close handles, resources */ - pxThis->fDeleteFunction( pxThis ); - /* Free the space */ - vPortFreeLarge( pxThis ); - } - else - { - ppxClient = &( pxThis->pxNextClient ); - } - } -} -/*-----------------------------------------------------------*/ - -static char *strnew( const char *pcString ) -{ -BaseType_t xLength; -char *pxBuffer; - - xLength = strlen( pcString ) + 1; - pxBuffer = ( char * ) pvPortMalloc( xLength ); - if( pxBuffer != NULL ) - { - memcpy( pxBuffer, pcString, xLength ); - } - - return pxBuffer; -} -/*-----------------------------------------------------------*/ - -static void prvRemoveSlash( char *pcDir ) -{ -BaseType_t xLength = strlen( pcDir ); - - while( ( xLength > 0 ) && ( pcDir[ xLength - 1 ] == '/' ) ) - { - pcDir[ --xLength ] = '\0'; - } -} -/*-----------------------------------------------------------*/ - -#if( ipconfigSUPPORT_SIGNALS != 0 ) - - /* FreeRTOS_TCPServerWork() calls select(). - The two functions below provide a possibility to interrupt - the call to select(). After the interruption, resume - by calling FreeRTOS_TCPServerWork() again. */ - BaseType_t FreeRTOS_TCPServerSignal( TCPServer_t *pxServer ) - { - BaseType_t xIndex; - BaseType_t xResult = pdFALSE; - for( xIndex = 0; xIndex < pxServer->xServerCount; xIndex++ ) - { - if( pxServer->xServers[ xIndex ].xSocket != FREERTOS_NO_SOCKET ) - { - FreeRTOS_SignalSocket( pxServer->xServers[ xIndex ].xSocket ); - xResult = pdTRUE; - break; - } - } - - return xResult; - } - -#endif /* ipconfigSUPPORT_SIGNALS */ -/*-----------------------------------------------------------*/ - -#if( ipconfigSUPPORT_SIGNALS != 0 ) - - /* Same as above: this function may be called from an ISR, - for instance a GPIO interrupt. */ - BaseType_t FreeRTOS_TCPServerSignalFromISR( TCPServer_t *pxServer, BaseType_t *pxHigherPriorityTaskWoken ) - { - BaseType_t xIndex; - BaseType_t xResult = pdFALSE; - for( xIndex = 0; xIndex < pxServer->xServerCount; xIndex++ ) - { - if( pxServer->xServers[ xIndex ].xSocket != FREERTOS_NO_SOCKET ) - { - FreeRTOS_SignalSocketFromISR( pxServer->xServers[ xIndex ].xSocket, pxHigherPriorityTaskWoken ); - xResult = pdTRUE; - break; - } - } - - return xResult; - } -#endif /* ipconfigSUPPORT_SIGNALS */ -/*-----------------------------------------------------------*/ - -#endif /* ( ipconfigUSE_TCP == 1 ) && ( ( ipconfigUSE_HTTP == 1 ) || ( ipconfigUSE_FTP == 1 ) ) */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/FTP/FreeRTOS_FTP_commands.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/FTP/FreeRTOS_FTP_commands.c deleted file mode 100644 index b399f3648..000000000 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/FTP/FreeRTOS_FTP_commands.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - * FreeRTOS+TCP V2.0.3 - * 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 includes. */ -#include "FreeRTOS.h" - -/* FreeRTOS+TCP includes. */ -#include "FreeRTOS_FTP_commands.h" - -const FTPCommand_t xFTPCommands[ FTP_CMD_COUNT ] = -{ -/* cmdLen cmdName[7] cmdType checkLogin checkNullArg */ - { 4, "USER", ECMD_USER, pdFALSE, pdFALSE }, - { 4, "PASS", ECMD_PASS, pdFALSE, pdFALSE }, - { 4, "ACCT", ECMD_ACCT, pdTRUE, pdFALSE }, - { 3, "CWD", ECMD_CWD, pdTRUE, pdTRUE }, - { 4, "CDUP", ECMD_CDUP, pdTRUE, pdFALSE }, - { 4, "SMNT", ECMD_SMNT, pdTRUE, pdFALSE }, - { 4, "QUIT", ECMD_QUIT, pdTRUE, pdFALSE }, - { 4, "REIN", ECMD_REIN, pdTRUE, pdFALSE }, - { 4, "PORT", ECMD_PORT, pdTRUE, pdFALSE }, - { 4, "PASV", ECMD_PASV, pdTRUE, pdFALSE }, - { 4, "TYPE", ECMD_TYPE, pdTRUE, pdFALSE }, - { 4, "STRU", ECMD_STRU, pdTRUE, pdFALSE }, - { 4, "MODE", ECMD_MODE, pdTRUE, pdFALSE }, - { 4, "RETR", ECMD_RETR, pdTRUE, pdTRUE }, - { 4, "STOR", ECMD_STOR, pdTRUE, pdTRUE }, - { 4, "STOU", ECMD_STOU, pdTRUE, pdFALSE }, - { 4, "APPE", ECMD_APPE, pdTRUE, pdFALSE }, - { 4, "ALLO", ECMD_ALLO, pdTRUE, pdFALSE }, - { 4, "REST", ECMD_REST, pdTRUE, pdFALSE }, - { 4, "RNFR", ECMD_RNFR, pdTRUE, pdTRUE }, - { 4, "RNTO", ECMD_RNTO, pdTRUE, pdTRUE }, - { 4, "ABOR", ECMD_ABOR, pdTRUE, pdFALSE }, - { 4, "SIZE", ECMD_SIZE, pdTRUE, pdTRUE }, - { 4, "MDTM", ECMD_MDTM, pdTRUE, pdTRUE }, - { 4, "DELE", ECMD_DELE, pdTRUE, pdTRUE }, - { 3, "RMD", ECMD_RMD, pdTRUE, pdTRUE }, - { 3, "MKD", ECMD_MKD, pdTRUE, pdTRUE }, - { 3, "PWD", ECMD_PWD, pdTRUE, pdFALSE }, - { 4, "LIST", ECMD_LIST, pdTRUE, pdFALSE }, - { 4, "NLST", ECMD_NLST, pdTRUE, pdFALSE }, - { 4, "SITE", ECMD_SITE, pdTRUE, pdFALSE }, - { 4, "SYST", ECMD_SYST, pdFALSE, pdFALSE }, - { 4, "FEAT", ECMD_FEAT, pdFALSE, pdFALSE }, - { 4, "STAT", ECMD_STAT, pdTRUE, pdFALSE }, - { 4, "HELP", ECMD_HELP, pdFALSE, pdFALSE }, - { 4, "NOOP", ECMD_NOOP, pdFALSE, pdFALSE }, - { 4, "EMPT", ECMD_EMPTY, pdFALSE, pdFALSE }, - { 4, "CLOS", ECMD_CLOSE, pdTRUE, pdFALSE }, - { 4, "UNKN", ECMD_UNKNOWN, pdFALSE, pdFALSE }, -}; diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/FTP/FreeRTOS_FTP_server.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/FTP/FreeRTOS_FTP_server.c deleted file mode 100644 index a2a6ba155..000000000 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/FTP/FreeRTOS_FTP_server.c +++ /dev/null @@ -1,2637 +0,0 @@ -/* - * FreeRTOS+TCP V2.0.3 - * 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 - */ - -/* Standard includes. */ -#include -#include -#include -#include - -/* FreeRTOS includes. */ -#include "FreeRTOS.h" -#include "task.h" -#include "portmacro.h" - -/* FreeRTOS+TCP includes. */ -#include "FreeRTOS_IP.h" -#include "FreeRTOS_TCP_IP.h" -#include "FreeRTOS_Sockets.h" -#include "FreeRTOS_Stream_Buffer.h" - -/* FreeRTOS Protocol includes. */ -#include "FreeRTOS_FTP_commands.h" -#include "FreeRTOS_TCP_server.h" -#include "FreeRTOS_server_private.h" - -/* Remove the whole file if FTP is not supported. */ -#if( ipconfigUSE_FTP == 1 ) - -#ifndef HTTP_SERVER_BACKLOG - #define HTTP_SERVER_BACKLOG ( 12 ) -#endif - -#if !defined( ARRAY_SIZE ) - #define ARRAY_SIZE( x ) ( BaseType_t ) (sizeof( x ) / sizeof( x )[ 0 ] ) -#endif - -#if defined(__WIN32__) && !defined(ipconfigFTP_FS_USES_BACKSLAH) - #define ipconfigFTP_FS_USES_BACKSLAH 1 -#endif - -/* Some defines to make the code more readbale */ -#define pcCOMMAND_BUFFER pxClient->pxParent->pcCommandBuffer -#define pcNEW_DIR pxClient->pxParent->pcNewDir -#define pcFILE_BUFFER pxClient->pxParent->pcFileBuffer - -/* This FTP server will only do binary transfers */ -#define TMODE_BINARY 1 -#define TMODE_ASCII 2 -#define TMODE_7BITS 3 -#define TMODE_8BITS 4 - -/* Ascii character definitions. */ -#define ftpASCII_CR 13 -#define ftpASCII_LF 10 - -#if defined( FTP_WRITES_ALIGNED ) || defined( ipconfigFTP_WRITES_ALIGNED ) - #error Name change : please rename the define to the new name 'ipconfigFTP_ZERO_COPY_ALIGNED_WRITES' -#endif - -/* - * ipconfigFTP_ZERO_COPY_ALIGNED_WRITES : experimental optimisation option. - * If non-zero, receiving data will be done with the zero-copy method and also - * writes to disk will be done with sector-alignment as much as possible. - */ -#ifndef ipconfigFTP_ZERO_COPY_ALIGNED_WRITES - #define ipconfigFTP_ZERO_COPY_ALIGNED_WRITES 0 -#endif - -/* - * This module only has 2 public functions: - */ -BaseType_t xFTPClientWork( TCPClient_t *pxClient ); -void vFTPClientDelete( TCPClient_t *pxClient ); - -/* - * Process a single command. - */ -static BaseType_t prvProcessCommand( FTPClient_t *pxClient, BaseType_t xIndex, char *pcRestCommand ); - -/* - * Create a socket for a data connection to the FTP client. - */ -static BaseType_t prvTransferConnect( FTPClient_t *pxClient, BaseType_t xDoListen ); - -/* - * Either call listen() or connect() to start the transfer connection. - */ -static BaseType_t prvTransferStart( FTPClient_t *pxClient ); - -/* - * See if the socket has got connected or disconnected. Close the socket if - * necessary. - */ -static void prvTransferCheck( FTPClient_t *pxClient ); - -/* - * Close the data socket and issue some informative logging. - */ -static void prvTransferCloseSocket( FTPClient_t *pxClient ); - -/* - * Close the file handle (pxReadHandle or pxWriteHandle). - */ -static void prvTransferCloseFile( FTPClient_t *pxClient ); - -/* - * Close a directory (-handle). - */ -static void prvTransferCloseDir( FTPClient_t *pxClient ); - -/* - * Translate a string (indicating a transfer type) to a number. - */ -static BaseType_t prvGetTransferType( const char *pcType ); - -#if( ipconfigHAS_PRINTF != 0 ) - /* - * For nice logging: write an amount (number of bytes), e.g. 3512200 as - * "3.45 MB" - */ - static const char *pcMkSize( uint32_t ulAmount, char *pcBuffer, BaseType_t xBufferSize ); -#endif - -#if( ipconfigHAS_PRINTF != 0 ) - /* - * Calculate the average as bytes-per-second, when amount and milliseconds - * are known. - */ - static uint32_t ulGetAverage( uint32_t ulAmount, TickType_t xDeltaMs ); -#endif - -/* - * A port command looks like: PORT h1,h2,h3,h4,p1,p2. Parse it and translate it - * to an IP-address and a port number. - */ -static UBaseType_t prvParsePortData( const char *pcCommand, uint32_t *pulIPAddress ); - -/* - * CWD: Change current working directory. - */ - -static BaseType_t prvChangeDir( FTPClient_t *pxClient, char *pcDirectory ); - -/* - * RNFR: Rename from ... - */ -static BaseType_t prvRenameFrom( FTPClient_t *pxClient, const char *pcFileName ); - -/* - * RNTO: Rename to ... - */ -static BaseType_t prvRenameTo( FTPClient_t *pxClient, const char *pcFileName ); - -/* - * SITE: Change file permissions. - */ -static BaseType_t prvSiteCmd( FTPClient_t *pxClient, char *pcRestCommand ); - -/* - * DELE: Delete a file. - */ -static BaseType_t prvDeleteFile( FTPClient_t *pxClient, char *pcFileName ); - -/* - * SIZE: get the size of a file (xSendDate = 0). - * MDTM: get data and time properties (xSendDate = 1). - */ -static BaseType_t prvSizeDateFile( FTPClient_t *pxClient, char *pcFileName, BaseType_t xSendDate ); - -/* - * MKD: Make / create a directory (xDoRemove = 0). - * RMD: Remove a directory (xDoRemove = 1). - */ -static BaseType_t prvMakeRemoveDir( FTPClient_t *pxClient, const char *pcDirectory, BaseType_t xDoRemove ); - -/* - * The next three commands: LIST, RETR and STOR all require a data socket. - * The data connection is either started with a 'PORT' or a 'PASV' command. - * Each of the commands has a prepare- (Prep) and a working- (Work) function. - * The Work function should be called as long as the data socket is open, and - * there is data to be transmitted. - */ - -/* - * LIST: Send a directory listing in Unix style. - */ -static BaseType_t prvListSendPrep( FTPClient_t *pxClient ); -static BaseType_t prvListSendWork( FTPClient_t *pxClient ); - -/* - * RETR: Send a file to the FTP client. - */ -static BaseType_t prvRetrieveFilePrep( FTPClient_t *pxClient, char *pcFileName ); -static BaseType_t prvRetrieveFileWork( FTPClient_t *pxClient ); - -/* - * STOR: Receive a file from the FTP client and store it. - */ -static BaseType_t prvStoreFilePrep( FTPClient_t *pxClient, char *pcFileName ); -static BaseType_t prvStoreFileWork( FTPClient_t *pxClient ); - -/* - * Print/format a single directory entry in Unix style. - */ -static BaseType_t prvGetFileInfoStat( FF_DirEnt_t *pxEntry, char *pcLine, BaseType_t xMaxLength ); - -/* - * Send a reply to a socket, either the command- or the data-socket. - */ -static BaseType_t prvSendReply( Socket_t xSocket, const char *pcBuffer, BaseType_t xLength ); - -/* - * Prepend the root directory (if any), plus the current working directory - * (always), to get an absolute path. - */ -BaseType_t xMakeAbsolute( FTPClient_t *pxClient, char *pcBuffer, BaseType_t xBufferLength, const char *pcPath ); - -/* - -####### ##### ###### # # ## - # ## # # # # # # # # - # # # # # # # - # # # # # # # #### ### ## # # - ##### # ##### # # # # # # # # # # - # # # # # # # # # ## # #### - # # # ## ## # # # # # - # # # ## ## # # # # # -#### #### #### ## ## #### #### ## ## - - * xFTPClientWork() - * will be called by FreeRTOS_TCPServerWork(), after select has expired(). - * FD_ISSET will not be used. This work function will always be called at - * regular intervals, and also after a select() event has occurred. - */ -BaseType_t xFTPClientWork( TCPClient_t *pxTCPClient ) -{ -FTPClient_t *pxClient = ( FTPClient_t * ) pxTCPClient; -BaseType_t xRc; - - if( pxClient->bits.bHelloSent == pdFALSE_UNSIGNED ) - { - BaseType_t xLength; - - pxClient->bits.bHelloSent = pdTRUE_UNSIGNED; - - xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), - "220 Welcome to the FreeRTOS+TCP FTP server\r\n" ); - prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength ); - } - - /* Call recv() in a non-blocking way, to see if there is an FTP command - sent to this server. */ - xRc = FreeRTOS_recv( pxClient->xSocket, ( void * )pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), 0 ); - - if( xRc > 0 ) - { - BaseType_t xIndex; - const FTPCommand_t *pxCommand; - char *pcRestCommand; - - if( xRc < ( BaseType_t ) sizeof( pcCOMMAND_BUFFER ) ) - { - pcCOMMAND_BUFFER[ xRc ] = '\0'; - } - - while( xRc && ( ( pcCOMMAND_BUFFER[ xRc - 1 ] == ftpASCII_CR ) || ( pcCOMMAND_BUFFER[ xRc - 1 ] == ftpASCII_LF ) ) ) - { - pcCOMMAND_BUFFER[ --xRc ] = '\0'; - } - - /* Now iterate through a list of FTP commands, and look for a match. */ - pxCommand = xFTPCommands; - pcRestCommand = pcCOMMAND_BUFFER; - for( xIndex = 0; xIndex < FTP_CMD_COUNT - 1; xIndex++, pxCommand++ ) - { - BaseType_t xLength; - - /* The length of each command is stored as well, just to be a bit - quicker here. */ - xLength = pxCommand->xCommandLength; - - if( ( xRc >= xLength ) && ( memcmp( ( const void * ) pxCommand->pcCommandName, ( const void * ) pcCOMMAND_BUFFER, xLength ) == 0 ) ) - { - /* A match with an existing command is found. Skip any - whitespace to get the first parameter. */ - pcRestCommand += xLength; - while( ( *pcRestCommand == ' ' ) || ( *pcRestCommand == '\t' ) ) - { - pcRestCommand++; - } - break; - } - } - - /* If the command received was not recognised, xIndex will point to a - fake entry called 'ECMD_UNKNOWN'. */ - prvProcessCommand( pxClient, xIndex, pcRestCommand ); - } - else if( xRc < 0 ) - { - /* The connection will be closed and the client will be deleted. */ - FreeRTOS_printf( ( "xFTPClientWork: xRc = %ld\n", xRc ) ); - } - - /* Does it have an open data connection? */ - if( pxClient->xTransferSocket != FREERTOS_NO_SOCKET ) - { - /* See if the connection has changed. */ - prvTransferCheck( pxClient ); - - /* "pcConnectionAck" contains a string like: - "Response: 150 Accepted data connection from 192.168.2.3:6789" - The socket can only be used once this acknowledgement has been sent. */ - if( ( pxClient->xTransferSocket != FREERTOS_NO_SOCKET ) && ( pxClient->pcConnectionAck[ 0 ] == '\0' ) ) - { - BaseType_t xClientRc = 0; - - if( pxClient->bits1.bDirHasEntry ) - { - /* Still listing a directory. */ - xClientRc = prvListSendWork( pxClient ); - } - else if( pxClient->pxReadHandle != NULL ) - { - /* Sending a file. */ - xClientRc = prvRetrieveFileWork( pxClient ); - } - else if( pxClient->pxWriteHandle != NULL ) - { - /* Receiving a file. */ - xClientRc = prvStoreFileWork( pxClient ); - } - - if( xClientRc < 0 ) - { - prvTransferCloseSocket( pxClient ); - prvTransferCloseFile( pxClient ); - } - } - } - - return xRc; -} -/*-----------------------------------------------------------*/ - -static void prvTransferCloseDir( FTPClient_t *pxClient ) -{ - /* Nothing to close for +FAT. */ - ( void ) pxClient; -} -/*-----------------------------------------------------------*/ - -void vFTPClientDelete( TCPClient_t *pxTCPClient ) -{ -FTPClient_t *pxClient = ( FTPClient_t * ) pxTCPClient; - - /* Close any directory-listing-handles (not used by +FAT ). */ - prvTransferCloseDir( pxClient ); - /* Close the data-socket. */ - prvTransferCloseSocket( pxClient ); - /* Close any open file handle. */ - prvTransferCloseFile( pxClient ); - - /* Close the FTP command socket */ - if( pxClient->xSocket != FREERTOS_NO_SOCKET ) - { - FreeRTOS_FD_CLR( pxClient->xSocket, pxClient->pxParent->xSocketSet, eSELECT_ALL ); - FreeRTOS_closesocket( pxClient->xSocket ); - pxClient->xSocket = FREERTOS_NO_SOCKET; - } -} -/*-----------------------------------------------------------*/ - -static BaseType_t prvProcessCommand( FTPClient_t *pxClient, BaseType_t xIndex, char *pcRestCommand ) -{ -const FTPCommand_t *pxFTPCommand = &( xFTPCommands[ xIndex ] ); -const char *pcMyReply = NULL; -BaseType_t xResult = 0; - - if( ( pxFTPCommand->ucCommandType != ECMD_PASS ) && ( pxFTPCommand->ucCommandType != ECMD_PORT ) ) - { - FreeRTOS_printf( ( " %s %s\n", pxFTPCommand->pcCommandName, pcRestCommand ) ); - } - - if( ( pxFTPCommand->checkLogin != pdFALSE ) && ( pxClient->bits.bLoggedIn == pdFALSE_UNSIGNED ) ) - { - pcMyReply = REPL_530; /* Please first log in. */ - } - else if( ( pxFTPCommand->checkNullArg != pdFALSE ) && ( ( pcRestCommand == NULL ) || ( pcRestCommand[ 0 ] == '\0' ) ) ) - { - pcMyReply = REPL_501; /* Command needs a parameter. */ - } - - if( pcMyReply == NULL ) - { - switch( pxFTPCommand->ucCommandType ) - { - case ECMD_USER: /* User. */ - /* User name has been entered, expect password. */ - pxClient->bits.bStatusUser = pdTRUE_UNSIGNED; - - #if( ipconfigFTP_HAS_USER_PASSWORD_HOOK != 0 )/*_RB_ Needs defaulting and adding to the web documentation. */ - { - /* Save the user name in 'pcFileName'. */ - snprintf( pxClient->pcFileName, sizeof( pxClient->pcFileName ), "%s", pcRestCommand ); - - /* The USER name is presented to the application. The function - may return a const string like "331 Please enter your - password\r\n". */ - pcMyReply = pcApplicationFTPUserHook( pxClient->pcFileName ); - if( pcMyReply == NULL ) - { - pcMyReply = REPL_331_ANON; - } - } - #else - { - /* No password checks, any password will be accepted. */ - pcMyReply = REPL_331_ANON; - } - #endif /* ipconfigFTP_HAS_USER_PASSWORD_HOOK != 0 */ - - #if( ipconfigFTP_HAS_USER_PROPERTIES_HOOK != 0 )/*_RB_ Needs defaulting and adding to the web documentation. */ - { - FTPUserProperties_t xProperties; - - xProperties.pcRootDir = pxClient->pcRootDir; - xProperties.xReadOnly = pdFALSE; - xProperties.usPortNumber = pxClient->usClientPort; - vApplicationFTPUserPropertiesHook( pxClient->pcFileName, &( xProperties ) ); - - if( xProperties.pcRootDir != NULL ) - { - pxClient->pcRootDir = xProperties.pcRootDir; - } - pxClient->bits.bReadOnly = ( xProperties.xReadOnly != pdFALSE_UNSIGNED ); - } - #endif /* ipconfigFTP_HAS_USER_PROPERTIES_HOOK */ - break; - - case ECMD_PASS: /* Password. */ - pxClient->ulRestartOffset = 0; - if( pxClient->bits.bStatusUser == pdFALSE_UNSIGNED ) - { - pcMyReply = REPL_503; /* "503 Bad sequence of commands.\r\n". */ - } - else - { - BaseType_t xAllow; - - pxClient->bits.bStatusUser = pdFALSE_UNSIGNED; - #if( ipconfigFTP_HAS_USER_PASSWORD_HOOK != 0 ) - { - xAllow = xApplicationFTPPasswordHook( pxClient->pcFileName, pcRestCommand ); - } - #else - { - xAllow = 1; - } - #endif /* ipconfigFTP_HAS_USER_PASSWORD_HOOK */ - - if( xAllow > 0 ) - { - pxClient->bits.bLoggedIn = pdTRUE_UNSIGNED; /* Client has now logged in. */ - pcMyReply = "230 OK. Current directory is /\r\n"; - } - else - { - pcMyReply = "530 Login incorrect\r\n"; /* 530 Login incorrect. */ - } - - strcpy( pxClient->pcCurrentDir, ( const char * ) "/" ); - } - break; - - case ECMD_SYST: /* System. */ - snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), "215 UNIX Type: L8\r\n" ); - pcMyReply = pcCOMMAND_BUFFER; - break; - - case ECMD_PWD: /* Get working directory. */ - xMakeRelative( pxClient, pcFILE_BUFFER, sizeof( pcFILE_BUFFER ), pxClient->pcCurrentDir ); - snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), REPL_257_PWD, pcFILE_BUFFER ); - pcMyReply = pcCOMMAND_BUFFER; - break; - - case ECMD_REST: - if( pxClient->bits.bReadOnly != pdFALSE_UNSIGNED ) - { - pcMyReply = REPL_553_READ_ONLY; - } - else - { - const char *pcPtr = pcRestCommand; - - while( *pcPtr == ' ' ) - { - pcPtr++; - } - - if( ( *pcPtr >= '0' ) && ( *pcPtr <= '9' ) ) - { - sscanf( pcPtr, "%lu", &pxClient->ulRestartOffset ); - snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), - "350 Restarting at %lu. Send STORE or RETRIEVE\r\n", pxClient->ulRestartOffset ); - pcMyReply = pcCOMMAND_BUFFER; - } - else - { - pcMyReply = REPL_500; /* 500 Syntax error, command unrecognised. */ - } - } - break; - - case ECMD_NOOP: /* NOP operation */ - if( pxClient->xTransferSocket != FREERTOS_NO_SOCKET ) - { - pcMyReply = REPL_200_PROGRESS; - } - else - { - pcMyReply = REPL_200; - } - break; - - case ECMD_TYPE: /* Ask or set transfer type. */ - { - /* e.g. "TYPE I" for Images (binary). */ - BaseType_t xType = prvGetTransferType( pcRestCommand ); - - if( xType < 0 ) - { - /* TYPE not recognised. */ - pcMyReply = REPL_500; - } - else - { - pxClient->xTransType = xType; - pcMyReply = REPL_200; - } - } - break; - - case ECMD_PASV: /* Enter passive mode. */ - /* Connect passive: Server will listen() and wait for a connection. - Start up a new data connection with 'xDoListen' set to true. */ - if( prvTransferConnect( pxClient, pdTRUE ) == pdFALSE ) - { - pcMyReply = REPL_502; - } - else - { - uint32_t ulIP; - uint16_t ulPort; - struct freertos_sockaddr xLocalAddress; - struct freertos_sockaddr xRemoteAddress; - - FreeRTOS_GetLocalAddress( pxClient->xTransferSocket, &xLocalAddress ); - FreeRTOS_GetRemoteAddress( pxClient->xSocket, &xRemoteAddress ); - - ulIP = FreeRTOS_ntohl( xLocalAddress.sin_addr ); - pxClient->ulClientIP = FreeRTOS_ntohl( xRemoteAddress.sin_addr ); - ulPort = FreeRTOS_ntohs( xLocalAddress.sin_port ); - - pxClient->usClientPort = FreeRTOS_ntohs( xRemoteAddress.sin_port ); - - /* REPL_227_D "227 Entering Passive Mode (%d,%d,%d,%d,%d,%d). */ - snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), REPL_227_D, - ( unsigned )ulIP >> 24, - ( unsigned )( ulIP >> 16 ) & 0xFF, - ( unsigned )( ulIP >> 8 ) & 0xFF, - ( unsigned )ulIP & 0xFF, - ( unsigned )ulPort >> 8, - ( unsigned )ulPort & 0xFF ); - - pcMyReply = pcCOMMAND_BUFFER; - } - break; - - case ECMD_PORT: /* Active connection to the client. */ - /* The client uses this command to tell the server to what - client-side port the server should contact; use of this command - indicates an active data transfer. e.g. PORT 192,168,1,2,4,19. */ - { - uint32_t ulIPAddress = 0; - UBaseType_t uxPort; - - uxPort = prvParsePortData( pcRestCommand, &ulIPAddress ); - FreeRTOS_printf( (" PORT %lxip:%ld\n", ulIPAddress, uxPort ) ); - - if( uxPort == 0u ) - { - pcMyReply = REPL_501; - } - else if( prvTransferConnect( pxClient, pdFALSE ) == pdFALSE ) - { - /* Call prvTransferConnect() with 'xDoListen' = false for an - active connect(). */ - pcMyReply = REPL_501; - } - else - { - pxClient->usClientPort = ( uint16_t ) uxPort; - pxClient->ulClientIP = ulIPAddress; - FreeRTOS_printf( ("Client address %lxip:%lu\n", ulIPAddress, uxPort ) ); - pcMyReply = REPL_200; - } - } - break; - - case ECMD_CWD: /* Change current working directory. */ - prvChangeDir( pxClient, pcRestCommand ); - break; - - case ECMD_RNFR: - if( pxClient->bits.bReadOnly != pdFALSE_UNSIGNED ) - { - pcMyReply = REPL_553_READ_ONLY; - } - else - { - prvRenameFrom( pxClient, pcRestCommand ); - } - break; - - case ECMD_RNTO: - if( pxClient->bits.bInRename == pdFALSE_UNSIGNED ) - { - pcMyReply = REPL_503; /* "503 Bad sequence of commands. */ - } - else - { - prvRenameTo( pxClient, pcRestCommand ); - } - break; - - case ECMD_SITE: /* Set file permissions */ - if( pxClient->bits.bReadOnly != pdFALSE_UNSIGNED ) - { - pcMyReply = REPL_553_READ_ONLY; - } - else if( prvSiteCmd( pxClient, pcRestCommand ) == pdFALSE ) - { - pcMyReply = REPL_202; - } - break; - - case ECMD_DELE: - if( pxClient->bits.bReadOnly != pdFALSE_UNSIGNED ) - { - pcMyReply = REPL_553_READ_ONLY; - } - else - { - prvDeleteFile( pxClient, pcRestCommand ); - } - break; - - case ECMD_MDTM: - prvSizeDateFile( pxClient, pcRestCommand, pdTRUE ); - break; - - case ECMD_SIZE: - if( pxClient->pxWriteHandle != NULL ) - { - /* This SIZE query is probably about a file which is now being - received. If so, return the value of pxClient->ulRecvBytes, - pcRestCommand points to 'pcCommandBuffer', make it free by - copying it to pcNewDir. */ - - xMakeAbsolute( pxClient, pcNEW_DIR, sizeof( pcNEW_DIR ), pcRestCommand ); - - if( strcmp( pcNEW_DIR, pcRestCommand ) == 0 ) - { - BaseType_t xCount; - for( xCount = 0; xCount < 3 && pxClient->pxWriteHandle; xCount++ ) - { - prvStoreFileWork( pxClient ); - } - if( pxClient->pxWriteHandle != NULL ) - { - /* File being queried is still open, return number of - bytes received until now. */ - snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), "213 %lu\r\n", pxClient->ulRecvBytes ); - pcMyReply = pcCOMMAND_BUFFER; - } /* otherwise, do a normal stat(). */ - } - strcpy( pcRestCommand, pcNEW_DIR ); - } - if( pcMyReply == NULL ) - { - prvSizeDateFile( pxClient, pcRestCommand, pdFALSE ); - } - break; - case ECMD_MKD: - case ECMD_RMD: - if( pxClient->bits.bReadOnly != pdFALSE_UNSIGNED ) - { - pcMyReply = REPL_553_READ_ONLY; - } - else - { - prvMakeRemoveDir( pxClient, pcRestCommand, pxFTPCommand->ucCommandType == ECMD_RMD ); - } - break; - case ECMD_CDUP: - prvChangeDir( pxClient, ".." ); - break; - - case ECMD_QUIT: - prvSendReply( pxClient->xSocket, REPL_221, 0 ); - pxClient->bits.bLoggedIn = pdFALSE_UNSIGNED; - break; - case ECMD_LIST: - case ECMD_RETR: - case ECMD_STOR: - if( ( pxClient->xTransferSocket == FREERTOS_NO_SOCKET ) && - ( ( pxFTPCommand->ucCommandType != ECMD_STOR ) || - ( pxClient->bits1.bEmptyFile == pdFALSE_UNSIGNED ) ) ) - { - /* Sending "425 Can't open data connection." : - Before receiving any of these commands, there must have been a - PORT or PASV command, which causes the creation of a data socket. */ - /* There is one exception: a STOR command is received while the - data connection has already been closed. This is tested with the - 'bEmptyFile' flag. */ - pcMyReply = REPL_425; - } - else - { - /* In case an empty file was received ( bits1.bEmptyFile ), the - transfer socket never delivered any data. Check if the transfer - socket is still open: */ - if( pxClient->xTransferSocket != FREERTOS_NO_SOCKET ) - { - prvTransferCheck( pxClient ); - } - switch( pxFTPCommand->ucCommandType ) - { - case ECMD_LIST: - prvListSendPrep( pxClient ); - break; - case ECMD_RETR: - prvRetrieveFilePrep( pxClient, pcRestCommand ); - break; - case ECMD_STOR: - if( pxClient->bits.bReadOnly != pdFALSE_UNSIGNED ) - { - pcMyReply = REPL_553_READ_ONLY; - } - else - { - prvStoreFilePrep( pxClient, pcRestCommand ); - if( pxClient->bits1.bEmptyFile != pdFALSE_UNSIGNED ) - { - /* Although the 'xTransferSocket' is closed already, - call this function just for the logging. */ - prvTransferCloseSocket( pxClient ); - - /* Close an empty file. */ - prvTransferCloseFile( pxClient ); - } - } - break; - } - } - break; - - case ECMD_FEAT: - { - static const char pcFeatAnswer[] = - "211-Features:\x0a" - /* The MDTM command is only allowed when - there is support for date&time. */ - #if( ffconfigTIME_SUPPORT != 0 ) - " MDTM\x0a" - #endif - " REST STREAM\x0a" - " SIZE\x0d\x0a" - "211 End\x0d\x0a"; - pcMyReply = pcFeatAnswer; - } - break; - - case ECMD_UNKNOWN: - FreeRTOS_printf( ("ftp::processCmd: Cmd %s unknown\n", pcRestCommand ) ); - pcMyReply = REPL_500; - break; - } - } - if( pxFTPCommand->ucCommandType != ECMD_RNFR ) - { - pxClient->bits.bInRename = pdFALSE_UNSIGNED; - } - - if( pcMyReply != NULL ) - { - xResult = prvSendReply( pxClient->xSocket, pcMyReply, strlen( pcMyReply ) ); - } - - return xResult; -} -/*-----------------------------------------------------------*/ - -static BaseType_t prvTransferConnect( FTPClient_t *pxClient, BaseType_t xDoListen ) -{ -Socket_t xSocket; -BaseType_t xResult; - - /* Open a socket for a data connection with the FTP client. - Happens after a PORT or a PASV command. */ - - /* Make sure the previous socket is deleted and flags reset */ - prvTransferCloseSocket( pxClient ); - - pxClient->bits1.bEmptyFile = pdFALSE_UNSIGNED; - - xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP ); - - if( ( xSocket != FREERTOS_NO_SOCKET ) && ( xSocket != FREERTOS_INVALID_SOCKET ) ) - { - BaseType_t xSmallTimeout = pdMS_TO_TICKS( 100 ); - struct freertos_sockaddr xAddress; - - #if( ipconfigFTP_TX_BUFSIZE > 0 ) - WinProperties_t xWinProps; - #endif - xAddress.sin_addr = FreeRTOS_GetIPAddress( ); /* Single NIC, currently not used */ - xAddress.sin_port = FreeRTOS_htons( 0 ); /* Bind to any available port number */ - - FreeRTOS_bind( xSocket, &xAddress, sizeof( xAddress ) ); - - #if( ipconfigFTP_TX_BUFSIZE > 0 ) - { - /* Fill in the buffer and window sizes that will be used by the - socket. */ - xWinProps.lTxBufSize = ipconfigFTP_TX_BUFSIZE; - xWinProps.lTxWinSize = ipconfigFTP_TX_WINSIZE; - xWinProps.lRxBufSize = ipconfigFTP_RX_BUFSIZE; - xWinProps.lRxWinSize = ipconfigFTP_RX_WINSIZE; - - /* Set the window and buffer sizes. */ - FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_WIN_PROPERTIES, ( void * ) &xWinProps, sizeof( xWinProps ) ); - } - #endif - - FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVTIMEO, ( void * ) &xSmallTimeout, sizeof( BaseType_t ) ); - FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, ( void * ) &xSmallTimeout, sizeof( BaseType_t ) ); - - /* The same instance of the socket will be used for the connection and - data transport. */ - if( xDoListen != pdFALSE ) - { - BaseType_t xTrueValue = pdTRUE; - FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_REUSE_LISTEN_SOCKET, ( void * ) &xTrueValue, sizeof( xTrueValue ) ); - } - pxClient->bits1.bIsListen = xDoListen; - pxClient->xTransferSocket = xSocket; - - if( xDoListen != pdFALSE ) - { - FreeRTOS_FD_SET( xSocket, pxClient->pxParent->xSocketSet, eSELECT_EXCEPT | eSELECT_READ ); - /* Calling FreeRTOS_listen( ) */ - xResult = prvTransferStart( pxClient ); - if( xResult >= 0 ) - { - xResult = pdTRUE; - } - } - else - { - FreeRTOS_FD_SET( xSocket, pxClient->pxParent->xSocketSet, eSELECT_EXCEPT | eSELECT_READ | eSELECT_WRITE ); - xResult = pdTRUE; - } - } - else - { - FreeRTOS_printf( ( "FreeRTOS_socket() failed\n" ) ); - xResult = -pdFREERTOS_ERRNO_ENOMEM; - } - - /* An active socket (PORT) should connect() later. */ - return xResult; -} -/*-----------------------------------------------------------*/ - -static BaseType_t prvTransferStart( FTPClient_t *pxClient ) -{ -BaseType_t xResult; - - /* A transfer socket has been opened, now either call listen() for 'PASV' - or connect() for the 'PORT' command. */ - if( pxClient->bits1.bIsListen != pdFALSE_UNSIGNED ) - { - xResult = FreeRTOS_listen( pxClient->xTransferSocket, 1 ); - } - else - { - struct freertos_sockaddr xAddress; - - xAddress.sin_addr = FreeRTOS_htonl( pxClient->ulClientIP ); - xAddress.sin_port = FreeRTOS_htons( pxClient->usClientPort ); - /* Start an active connection for this data socket */ - xResult = FreeRTOS_connect( pxClient->xTransferSocket, &xAddress, sizeof( xAddress ) ); - } - - return xResult; -} -/*-----------------------------------------------------------*/ - -static void prvTransferCheck( FTPClient_t *pxClient ) -{ -BaseType_t xRxSize; - - /* A data transfer is busy. Check if there are changes in connectedness. */ - xRxSize = FreeRTOS_rx_size( pxClient->xTransferSocket ); - - if( pxClient->bits1.bClientConnected == pdFALSE_UNSIGNED ) - { - /* The time to receive a small file can be so short, that we don't even - see that the socket gets connected and disconnected. Therefore, check - the sizeof of the RX buffer. */ - { - struct freertos_sockaddr xAddress; - Socket_t xNexSocket; - socklen_t xSocketLength = sizeof( xAddress ); - - if( pxClient->bits1.bIsListen != pdFALSE_UNSIGNED ) - { - xNexSocket = FreeRTOS_accept( pxClient->xTransferSocket, &xAddress, &xSocketLength); - if( ( ( xNexSocket != FREERTOS_NO_SOCKET ) && ( xNexSocket != FREERTOS_INVALID_SOCKET ) ) || - xRxSize > 0 ) - { - pxClient->bits1.bClientConnected = pdTRUE_UNSIGNED; - } - } - else - { - if( FreeRTOS_issocketconnected( pxClient->xTransferSocket ) > 0 || - xRxSize > 0 ) - { - pxClient->bits1.bClientConnected = pdTRUE_UNSIGNED; - } - } - if( pxClient->bits1.bClientConnected != pdFALSE_UNSIGNED ) - { - pxClient->bits1.bEmptyFile = pdFALSE_UNSIGNED; - #if( ipconfigHAS_PRINTF != 0 ) - { - struct freertos_sockaddr xRemoteAddress, xLocalAddress; - FreeRTOS_GetRemoteAddress( pxClient->xTransferSocket, &xRemoteAddress ); - FreeRTOS_GetLocalAddress( pxClient->xTransferSocket, &xLocalAddress ); - FreeRTOS_printf( ( "%s Connected from %u to %u\n", - pxClient->bits1.bIsListen != pdFALSE_UNSIGNED ? "PASV" : "PORT", - ( unsigned ) FreeRTOS_ntohs( xLocalAddress.sin_port ), - ( unsigned ) FreeRTOS_ntohs( xRemoteAddress.sin_port ) ) ); - } - #endif /* ipconfigHAS_PRINTF */ - FreeRTOS_FD_CLR( pxClient->xTransferSocket, pxClient->pxParent->xSocketSet, eSELECT_WRITE ); - FreeRTOS_FD_SET( pxClient->xTransferSocket, pxClient->pxParent->xSocketSet, eSELECT_READ|eSELECT_EXCEPT ); - } - } - } - - if ( pxClient->bits1.bClientConnected != pdFALSE_UNSIGNED ) - { - if( pxClient->pcConnectionAck[ 0 ] != '\0' ) - { - BaseType_t xLength; - BaseType_t xRemotePort; - struct freertos_sockaddr xRemoteAddress; - - FreeRTOS_GetRemoteAddress( pxClient->xTransferSocket, &xRemoteAddress ); - xRemotePort = FreeRTOS_ntohs( xRemoteAddress.sin_port ); - - /* Tell on the command port 21 we have a data connection */ - xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), - pxClient->pcConnectionAck, pxClient->ulClientIP, xRemotePort ); - - prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength ); - pxClient->pcConnectionAck[ 0 ] = '\0'; - } - - if( ( FreeRTOS_issocketconnected( pxClient->xTransferSocket ) == pdFALSE ) && FreeRTOS_rx_size( pxClient->xTransferSocket ) == 0 ) - { - prvTransferCloseSocket( pxClient ); - prvTransferCloseFile( pxClient ); - } - } -} -/*-----------------------------------------------------------*/ - -static void prvTransferCloseSocket( FTPClient_t *pxClient ) -{ - if( pxClient->xTransferSocket != FREERTOS_NO_SOCKET ) - { - /* DEBUGGING ONLY */ - BaseType_t xRxSize = FreeRTOS_rx_size( pxClient->xTransferSocket ); - if( xRxSize > 0 ) - { - BaseType_t xRxSize2; - BaseType_t xStatus; - prvStoreFileWork( pxClient ); - xStatus = FreeRTOS_connstatus( pxClient->xTransferSocket ); - xRxSize2 = FreeRTOS_rx_size( pxClient->xTransferSocket ); - FreeRTOS_printf( ( "FTP: WARNING: %s: RX size = %ld -> %ld (%s)\n", - FreeRTOS_GetTCPStateName( xStatus ), - xRxSize, xRxSize2, pxClient->pcFileName ) ); - if( xRxSize2 > 1 ) - { - return; - } - - /* Remove compiler warnings in case FreeRTOS_printf() is not - defined. */ - ( void ) xStatus; - } - } - - if( ( pxClient->pxWriteHandle != NULL ) || ( pxClient->pxReadHandle != NULL ) ) - { - BaseType_t xLength; - char pcStrBuf[ 32 ]; - - if( pxClient->bits1.bHadError == pdFALSE_UNSIGNED ) - { - xLength = snprintf( pxClient->pcClientAck, sizeof( pxClient->pcClientAck ), - "226 Closing connection %d bytes transmitted\r\n", ( int ) pxClient->ulRecvBytes ); - } - else - { - xLength = snprintf( pxClient->pcClientAck, sizeof( pxClient->pcClientAck ), - "451 Requested action aborted after %d bytes\r\n", ( int ) pxClient->ulRecvBytes ); - } - - /* Tell on the command socket the data connection is now closed. */ - prvSendReply( pxClient->xSocket, pxClient->pcClientAck, xLength ); - - #if( ipconfigHAS_PRINTF != 0 ) - { - TickType_t xDelta; - uint32_t ulAverage; - xDelta = xTaskGetTickCount( ) - pxClient->xStartTime; - ulAverage = ulGetAverage( pxClient->ulRecvBytes, xDelta ); - - FreeRTOS_printf( ("FTP: %s: '%s' %lu Bytes (%s/sec)\n", - pxClient->pxReadHandle ? "sent" : "recv", - pxClient->pcFileName, - pxClient->ulRecvBytes, - pcMkSize( ulAverage, pcStrBuf, sizeof( pcStrBuf ) ) ) ); - } - #endif - } - - if( pxClient->xTransferSocket != FREERTOS_NO_SOCKET ) - { - FreeRTOS_FD_CLR( pxClient->xTransferSocket, pxClient->pxParent->xSocketSet, eSELECT_ALL ); - FreeRTOS_closesocket( pxClient->xTransferSocket ); - pxClient->xTransferSocket = FREERTOS_NO_SOCKET; - if( pxClient->ulRecvBytes == 0ul ) - { - /* Received zero bytes: an empty file */ - pxClient->bits1.bEmptyFile = pdTRUE_UNSIGNED; - } - else - { - pxClient->bits1.bEmptyFile = pdFALSE_UNSIGNED; - } - } - pxClient->bits1.bIsListen = pdFALSE_UNSIGNED; - pxClient->bits1.bDirHasEntry = pdFALSE_UNSIGNED; - pxClient->bits1.bClientConnected = pdFALSE_UNSIGNED; - pxClient->bits1.bHadError = pdFALSE_UNSIGNED; -} -/*-----------------------------------------------------------*/ - -static void prvTransferCloseFile( FTPClient_t *pxClient ) -{ - if( pxClient->pxWriteHandle != NULL ) - { - ff_fclose( pxClient->pxWriteHandle ); - pxClient->pxWriteHandle = NULL; - #if( ipconfigFTP_HAS_RECEIVED_HOOK != 0 ) - { - vApplicationFTPReceivedHook( pxClient->pcFileName, pxClient->ulRecvBytes, pxClient ); - } - #endif - - } - if( pxClient->pxReadHandle != NULL ) - { - ff_fclose( pxClient->pxReadHandle ); - pxClient->pxReadHandle = NULL; - } - /* These two field are only used for logging / file-statistics */ - pxClient->ulRecvBytes = 0ul; - pxClient->xStartTime = 0ul; -} -/*-----------------------------------------------------------*/ - -/** - * Guess the transfer type, given the client requested type. - * Actually in unix there is no difference between binary and - * ascii mode when we work with file descriptors. - * If #type is not recognized as a valid client request, -1 is returned. - */ -static BaseType_t prvGetTransferType( const char *pcType ) -{ -BaseType_t xResult = -1; - - if( pcType != NULL ) - { - BaseType_t xLength = strlen( pcType ); - if( xLength == 0 ) - { - return -1; - } - switch( pcType[ 0 ] ) { - case 'I': - xResult = TMODE_BINARY; - break; - case 'A': - xResult = TMODE_ASCII; - break; - case 'L': - if( xLength >= 3 ) - { - if( pcType[ 2 ] == '7' ) - { - xResult = TMODE_7BITS; - } - else if( pcType[ 2 ] == '8' ) - { - xResult = TMODE_7BITS; - } - } - break; - } - } - return xResult; -} -/*-----------------------------------------------------------*/ - -#if( ipconfigHAS_PRINTF != 0 ) - #define SIZE_1_GB ( 1024ul * 1024ul * 1024ul ) - #define SIZE_1_MB ( 1024ul * 1024ul ) - #define SIZE_1_KB ( 1024ul ) - - static const char *pcMkSize( uint32_t ulAmount, char *pcBuffer, BaseType_t xBufferSize ) - { - uint32_t ulGB, ulMB, ulKB, ulByte; - - ulGB = ( ulAmount / SIZE_1_GB ); - ulAmount -= ( ulGB * SIZE_1_GB ); - ulMB = ( ulAmount / SIZE_1_MB ); - ulAmount -= ( ulMB * SIZE_1_MB ); - ulKB = ( ulAmount / SIZE_1_KB ); - ulAmount -= ( ulKB * SIZE_1_KB ); - ulByte = ( ulAmount ); - - if (ulGB != 0ul ) - { - snprintf( pcBuffer, xBufferSize, "%lu.%02lu GB", ulGB, (100 * ulMB) / SIZE_1_KB ); - } - else if( ulMB != 0ul ) - { - snprintf( pcBuffer, xBufferSize, "%lu.%02lu MB", ulMB, (100 * ulKB) / SIZE_1_KB ); - } - else if( ulKB != 0ul ) - { - snprintf(pcBuffer, xBufferSize, "%lu.%02lu KB", ulKB, (100 * ulByte) / SIZE_1_KB ); - } - else - { - snprintf( pcBuffer, xBufferSize, "%lu bytes", ulByte ); - } - - return pcBuffer; - } - /*-----------------------------------------------------------*/ -#endif /* ipconfigHAS_PRINTF != 0 */ - -#if( ipconfigHAS_PRINTF != 0 ) - static uint32_t ulGetAverage( uint32_t ulAmount, TickType_t xDeltaMs ) - { - uint32_t ulAverage; - - /* Get the average amount of bytes per seconds. Ideally this is - calculated by Multiplying with 1000 and dividing by milliseconds: - ulAverage = ( 1000ul * ulAmount ) / xDeltaMs; - Now get a maximum precision, while avoiding an arithmetic overflow: - */ - if( xDeltaMs == 0ul ) - { - /* Time is zero, there is no average */ - ulAverage = 0ul; - } - else if( ulAmount >= ( ~0ul / 10ul ) ) - { - /* More than 409 MB has been transferred, do not multiply. */ - ulAverage = ( ulAmount / ( xDeltaMs / 1000ul ) ); - } - else if( ulAmount >= ( ~0ul / 100ul ) ) - { - /* Between 409 and 41 MB has been transferred, can multiply by 10. */ - ulAverage = ( ( ulAmount * 10ul ) / ( xDeltaMs / 100ul ) ); - } - else if( ulAmount >= ( ~0ul / 1000ul ) ) - { - /* Between 4.1 MB and 41 has been transferred, can multiply by 100. */ - ulAverage = ( ( ulAmount * 100ul ) / ( xDeltaMs / 10ul ) ); - } - else - { - /* Less than 4.1 MB: can multiply by 1000. */ - ulAverage = ( ( ulAmount * 1000ul ) / xDeltaMs ); - } - - return ulAverage; - } - /*-----------------------------------------------------------*/ -#endif /* ipconfigHAS_PRINTF != 0 */ - -static UBaseType_t prvParsePortData( const char *pcCommand, uint32_t *pulIPAddress ) -{ -/*_HT_ Using 'unsigned' here because when sscanf() sees '%u', it expects a pointer to 'unsigned'. -Not sure about the sscanf() format for UBaseType_t ? */ -unsigned h1, h2, h3, h4, p1, p2; -char sep; -UBaseType_t uxResult; - - /* Expect PORT h1,h2,h3,h4,p1,p2 */ - if (sscanf (pcCommand, "%u%c%u%c%u%c%u%c%u%c%u", &h1, &sep, &h2, &sep, &h3, &sep, &h4, &sep, &p1, &sep, &p2) != 11) - { - uxResult= 0u; - } - else - { - /* Put in network byte order. */ - *pulIPAddress = - ( ( uint32_t ) h1 << 24 ) | - ( ( uint32_t ) h2 << 16 ) | - ( ( uint32_t ) h3 << 8 ) | - ( ( uint32_t ) h4 ); - uxResult = ( p1 << 8 ) | p2; - } - return uxResult; -} -/*-----------------------------------------------------------*/ - -/* - - #### ####### # ### -# # # # ## # # -# # # # # # -# ###### #### ### ## #### # # ### # #### - ## # # # # # # # # ##### # # # # - ## # # # ## # ###### # # # # ###### -# # # # # # # # # # # -# # # ## # # # # ## # # # # ## - #### ## #### #### #### #### ##### ##### #### - -*/ - -static BaseType_t prvStoreFilePrep( FTPClient_t *pxClient, char *pcFileName ) -{ -BaseType_t xResult; -FF_FILE *pxNewHandle; -size_t uxFileSize = 0ul; -int iErrorNo; - - /* Close previous handle (if any) and reset file transfer parameters. */ - prvTransferCloseFile( pxClient ); - - xMakeAbsolute( pxClient, pxClient->pcFileName, sizeof( pxClient->pcFileName ), pcFileName ); - - pxNewHandle = NULL; - - if( pxClient->ulRestartOffset != 0 ) - { - size_t uxOffset = pxClient->ulRestartOffset; - int32_t lRc; - - pxClient->ulRestartOffset = 0ul; /* Only use 1 time. */ - pxNewHandle = ff_fopen( pxClient->pcFileName, "ab" ); - - if( pxNewHandle != NULL ) - { - uxFileSize = pxNewHandle->ulFileSize; - - if( uxOffset <= uxFileSize ) - { - lRc = ff_fseek( pxNewHandle, uxOffset, FF_SEEK_SET ); - } - else - { - /* Won't even try to seek after EOF */ - lRc = -pdFREERTOS_ERRNO_EINVAL; - } - if( lRc != 0 ) - { - BaseType_t xLength; - - xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), - "450 Seek invalid %u length %u\r\n", - ( unsigned ) uxOffset, ( unsigned ) uxFileSize ); - - /* "Requested file action not taken". */ - prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength ); - - FreeRTOS_printf( ( "ftp::storeFile: create %s: Seek %u length %u\n", - pxClient->pcFileName, ( unsigned ) uxOffset, ( unsigned ) uxFileSize ) ); - - ff_fclose( pxNewHandle ); - pxNewHandle = NULL; - } - } - } - else - { - pxNewHandle = ff_fopen( pxClient->pcFileName, "wb" ); - } - - if( pxNewHandle == NULL ) - { - iErrorNo = stdioGET_ERRNO(); - if( iErrorNo == pdFREERTOS_ERRNO_ENOSPC ) - { - prvSendReply( pxClient->xSocket, REPL_552, 0 ); - } - else - { - /* "Requested file action not taken". */ - prvSendReply( pxClient->xSocket, REPL_450, 0 ); - } - FreeRTOS_printf( ( "ftp::storeFile: create %s: %s (errno %d)\n", - pxClient->pcFileName, - ( const char* ) strerror( iErrorNo ), iErrorNo ) ); - - xResult = pdFALSE; - } - else - { - if( pxClient->bits1.bIsListen ) - { - /* True if PASV is used. */ - snprintf( pxClient->pcConnectionAck, sizeof( pxClient->pcConnectionAck ), - "150 Accepted data connection from %%xip:%%u\r\n" ); - prvTransferCheck( pxClient ); - } - else - { - BaseType_t xLength; - - xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), "150 Opening BIN connection to store file\r\n" ); - prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength ); - pxClient->pcConnectionAck[ 0 ] = '\0'; - prvTransferStart( pxClient ); /* Now active connect. */ - } - - pxClient->pxWriteHandle = pxNewHandle; - - /* To get some statistics about the performance. */ - pxClient->xStartTime = xTaskGetTickCount( ); - - xResult = pdTRUE; - } - - return xResult; -} -/*-----------------------------------------------------------*/ - -#if( ipconfigFTP_ZERO_COPY_ALIGNED_WRITES == 0 ) - - static BaseType_t prvStoreFileWork( FTPClient_t *pxClient ) - { - BaseType_t xRc, xWritten; - - /* Read from the data socket until all has been read or until a negative value - is returned. */ - for( ; ; ) - { - char *pcBuffer; - - /* The "zero-copy" method: */ - xRc = FreeRTOS_recv( pxClient->xTransferSocket, ( void * ) &pcBuffer, - 0x20000u, FREERTOS_ZERO_COPY | FREERTOS_MSG_DONTWAIT ); - if( xRc <= 0 ) - { - break; - } - pxClient->ulRecvBytes += xRc; - xWritten = ff_fwrite( pcBuffer, 1, xRc, pxClient->pxWriteHandle ); - FreeRTOS_recv( pxClient->xTransferSocket, ( void * ) NULL, xRc, 0 ); - if( xWritten != xRc ) - { - xRc = -1; - /* bHadError: a transfer got aborted because of an error. */ - pxClient->bits1.bHadError = pdTRUE_UNSIGNED; - break; - } - } - return xRc; - } - -#else /* ipconfigFTP_ZERO_COPY_ALIGNED_WRITES != 0 */ - - #if !defined( ipconfigFTP_PREFERRED_WRITE_SIZE ) - /* If you store data on flash, it may be profitable to give 'ipconfigFTP_PREFERRED_WRITE_SIZE' - the same size as the size of the flash' erase blocks, e.g. 4KB */ - #define ipconfigFTP_PREFERRED_WRITE_SIZE 512ul - #endif - - static BaseType_t prvStoreFileWork( FTPClient_t *pxClient ) - { - BaseType_t xRc, xWritten; - - /* Read from the data socket until all has been read or until a negative - value is returned. */ - for( ; ; ) - { - char *pcBuffer; - UBaseType_t xStatus; - - /* The "zero-copy" method: */ - xRc = FreeRTOS_recv( pxClient->xTransferSocket, ( void * ) &pcBuffer, - 0x20000u, FREERTOS_ZERO_COPY | FREERTOS_MSG_DONTWAIT ); - - if( xRc <= 0 ) - { - /* There are no data or the connection is closed. */ - break; - } - xStatus = FreeRTOS_connstatus( pxClient->xTransferSocket ); - if( xStatus != eESTABLISHED ) - { - /* The connection is not established (any more), therefore - accept any amount of bytes, probably the last few bytes. */ - } - else - { - if( xRc >= ipconfigFTP_PREFERRED_WRITE_SIZE ) - { - /* More than a sector to write, round down to a multiple of - PREFERRED_WRITE_SIZE bytes. */ - xRc = ( xRc / ipconfigFTP_PREFERRED_WRITE_SIZE ) * ipconfigFTP_PREFERRED_WRITE_SIZE; - } - else - { - const StreamBuffer_t *pxBuffer = FreeRTOS_get_rx_buf( pxClient->xTransferSocket ); - size_t uxSpace = pxBuffer->LENGTH - pxBuffer->uxTail; - - if( uxSpace >= ipconfigFTP_PREFERRED_WRITE_SIZE ) - { - /* At this moment there are les than PREFERRED_WRITE_SIZE bytes in the RX - buffer, but there is space for more. Just return and - wait for more. */ - xRc = 0; - } - else - { - /* Now reading beyond the end of the circular buffer, - use a normal read. */ - pcBuffer = pcFILE_BUFFER; - xRc = FreeRTOS_recvcount( pxClient->xTransferSocket ); - xRc = ( xRc / ipconfigFTP_PREFERRED_WRITE_SIZE ) * ipconfigFTP_PREFERRED_WRITE_SIZE; - if( xRc > 0 ) - { - xRc = FreeRTOS_recv( pxClient->xTransferSocket, ( void * ) pcBuffer, - sizeof( pcFILE_BUFFER ), FREERTOS_MSG_DONTWAIT ); - } - } - } - } - if( xRc == 0 ) - { - break; - } - pxClient->ulRecvBytes += xRc; - - xWritten = ff_fwrite( pcBuffer, 1, xRc, pxClient->pxWriteHandle ); - if( pcBuffer != pcFILE_BUFFER ) - { - FreeRTOS_recv( pxClient->xTransferSocket, ( void * ) NULL, xRc, 0 ); - } - if( xWritten != xRc ) - { - xRc = -1; - /* bHadError: a transfer got aborted because of an error. */ - pxClient->bits1.bHadError = pdTRUE_UNSIGNED; - break; - } - } - return xRc; - } - -#endif /* ipconfigFTP_ZERO_COPY_ALIGNED_WRITES */ -/*-----------------------------------------------------------*/ - -/* -###### # ####### # ### - # # # # # ## # # - # # # # # # - # # #### ###### ### ## ### #### # # #### # # ### # #### - ###### # # # # # # # # # # # # # ##### # # # # - # ## ###### # ## # # ###### # # ###### # # # # ###### - # # # # # # # # # # # # # # - # # # ## # ## # # # ## # # # ## # # # # ## -### ## #### ## #### ##### #### ## #### #### ##### ##### #### -*/ -static BaseType_t prvRetrieveFilePrep( FTPClient_t *pxClient, char *pcFileName ) -{ -BaseType_t xResult = pdTRUE; -size_t uxFileSize; - - /* Close previous handle (if any) and reset file transfer parameters */ - prvTransferCloseFile( pxClient ); - - xMakeAbsolute( pxClient, pxClient->pcFileName, sizeof( pxClient->pcFileName ), pcFileName ); - - pxClient->pxReadHandle = ff_fopen( pxClient->pcFileName, "rb" ); - if( pxClient->pxReadHandle == NULL ) - { - int iErrno = stdioGET_ERRNO(); - /* "Requested file action not taken". */ - prvSendReply( pxClient->xSocket, REPL_450, 0 ); - FreeRTOS_printf( ("prvRetrieveFilePrep: open '%s': errno %d: %s\n", - pxClient->pcFileName, iErrno, ( const char * ) strerror( iErrno ) ) ); - uxFileSize = 0ul; - xResult = pdFALSE; - } - else - { - uxFileSize = pxClient->pxReadHandle->ulFileSize; - pxClient->uxBytesLeft = uxFileSize; - if( pxClient->ulRestartOffset != 0ul ) - { - size_t uxOffset = pxClient->ulRestartOffset; - int32_t iRc; - - /* Only use 1 time. */ - pxClient->ulRestartOffset = 0; - - if( uxOffset < uxFileSize ) - { - iRc = ff_fseek( pxClient->pxReadHandle, uxOffset, FF_SEEK_SET ); - } - else - { - iRc = -pdFREERTOS_ERRNO_EINVAL; - } - if( iRc != 0 ) - { - BaseType_t xLength; - - xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), - "450 Seek invalid %u length %u\r\n", ( unsigned ) uxOffset, ( unsigned ) uxFileSize ); - - /* "Requested file action not taken". */ - prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength ); - - FreeRTOS_printf( ( "prvRetrieveFilePrep: create %s: Seek %u length %u\n", - pxClient->pcFileName, ( unsigned ) uxOffset, ( unsigned ) uxFileSize ) ); - - ff_fclose( pxClient->pxReadHandle ); - pxClient->pxReadHandle = NULL; - xResult = pdFALSE; - } - else - { - pxClient->uxBytesLeft = uxFileSize - pxClient->ulRestartOffset; - } - } - } - if( xResult != pdFALSE ) - { - if( pxClient->bits1.bIsListen != pdFALSE_UNSIGNED ) - { - /* True if PASV is used. */ - snprintf( pxClient->pcConnectionAck, sizeof( pxClient->pcConnectionAck ), - "150%cAccepted data connection from %%xip:%%u\r\n%s", - pxClient->xTransType == TMODE_ASCII ? '-' : ' ', - pxClient->xTransType == TMODE_ASCII ? "150 NOTE: ASCII mode requested, but binary mode used\r\n" : "" ); - } else { - BaseType_t xLength; - - xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), "150%cOpening data connection to %lxip:%u\r\n%s", - pxClient->xTransType == TMODE_ASCII ? '-' : ' ', - pxClient->ulClientIP, - pxClient->usClientPort, - pxClient->xTransType == TMODE_ASCII ? "150 NOTE: ASCII mode requested, but binary mode used\r\n" : "" ); - prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength ); - pxClient->pcConnectionAck[ 0 ] = '\0'; - prvTransferStart( pxClient ); - } - - /* Prepare the ACK which will be sent when all data has been sent. */ - snprintf( pxClient->pcClientAck, sizeof( pxClient->pcClientAck ), "%s", REPL_226 ); - - /* To get some statistics about the performance. */ - pxClient->xStartTime = xTaskGetTickCount( ); - if( uxFileSize == 0ul ) - { - FreeRTOS_shutdown( pxClient->xTransferSocket, FREERTOS_SHUT_RDWR ); - } - } - - return xResult; -} -/*-----------------------------------------------------------*/ - -static BaseType_t prvRetrieveFileWork( FTPClient_t *pxClient ) -{ -size_t uxSpace; -size_t uxCount, uxItemsRead; -BaseType_t xRc = 0; -BaseType_t xSetEvent = pdFALSE; - - do - { - #if( ipconfigFTP_TX_ZERO_COPY != 0 ) - char *pcBuffer; - BaseType_t xBufferLength; - #endif /* ipconfigFTP_TX_ZERO_COPY */ - - /* Take the lesser of the two: tx_space (number of bytes that can be - queued for transmission) and uxBytesLeft (the number of bytes left to - read from the file) */ - uxSpace = FreeRTOS_tx_space( pxClient->xTransferSocket ); - - if( uxSpace == 0 ) - { - FreeRTOS_FD_SET( pxClient->xTransferSocket, pxClient->pxParent->xSocketSet, eSELECT_WRITE | eSELECT_EXCEPT ); - xRc = FreeRTOS_select( pxClient->pxParent->xSocketSet, 200 ); - uxSpace = FreeRTOS_tx_space( pxClient->xTransferSocket ); - } - - uxCount = FreeRTOS_min_uint32( pxClient->uxBytesLeft, uxSpace ); - - if( uxCount == 0 ) - { - break; - } - - #if( ipconfigFTP_TX_ZERO_COPY == 0 ) - { - if( uxCount > sizeof( pcFILE_BUFFER ) ) - { - uxCount = sizeof( pcFILE_BUFFER ); - } - uxItemsRead = ff_fread( pcFILE_BUFFER, 1, uxCount, pxClient->pxReadHandle ); - if( uxItemsRead != uxCount ) - { - FreeRTOS_printf( ( "prvRetrieveFileWork: Got %u Expected %u\n", ( unsigned )uxItemsRead, ( unsigned ) uxCount ) ); - xRc = FreeRTOS_shutdown( pxClient->xTransferSocket, FREERTOS_SHUT_RDWR ); - pxClient->uxBytesLeft = 0u; - break; - } - pxClient->uxBytesLeft -= uxCount; - - if( pxClient->uxBytesLeft == 0u ) - { - BaseType_t xTrueValue = 1; - - FreeRTOS_setsockopt( pxClient->xTransferSocket, 0, FREERTOS_SO_CLOSE_AFTER_SEND, ( void * ) &xTrueValue, sizeof( xTrueValue ) ); - } - - xRc = FreeRTOS_send( pxClient->xTransferSocket, pcFILE_BUFFER, uxCount, 0 ); - } - #else /* ipconfigFTP_TX_ZERO_COPY != 0 */ - { - /* Use zero-copy transmission: - FreeRTOS_get_tx_head() returns a direct pointer to the TX stream and - set xBufferLength to know how much space there is left. */ - pcBuffer = ( char * )FreeRTOS_get_tx_head( pxClient->xTransferSocket, &xBufferLength ); - if( ( pcBuffer != NULL ) && ( xBufferLength >= 512 ) ) - { - /* Will read disk data directly to the TX stream of the socket. */ - uxCount = FreeRTOS_min_uint32( uxCount, ( uint32_t )xBufferLength ); - if( uxCount > ( size_t ) 0x40000u ) - { - uxCount = ( size_t ) 0x40000u; - } - } - else - { - /* Use the normal file i/o buffer. */ - pcBuffer = pcFILE_BUFFER; - if( uxCount > sizeof( pcFILE_BUFFER ) ) - { - uxCount = sizeof( pcFILE_BUFFER ); - } - } - - if ( pxClient->uxBytesLeft >= 1024u ) - { - uxCount &= ~( ( size_t ) 512u - 1u ); - } - - if( uxCount <= 0u ) - { - /* Nothing to send after rounding down to a multiple of a sector size. */ - break; - } - - uxItemsRead = ff_fread( pcBuffer, 1, uxCount, pxClient->pxReadHandle ); - - if( uxCount != uxItemsRead ) - { - FreeRTOS_printf( ( "prvRetrieveFileWork: Got %u Expected %u\n", ( unsigned )uxItemsRead, ( unsigned )uxCount ) ); - xRc = FreeRTOS_shutdown( pxClient->xTransferSocket, FREERTOS_SHUT_RDWR ); - pxClient->uxBytesLeft = 0u; - break; - } - pxClient->uxBytesLeft -= uxCount; - - if( pxClient->uxBytesLeft == 0u ) - { - BaseType_t xTrueValue = 1; - - FreeRTOS_setsockopt( pxClient->xTransferSocket, 0, FREERTOS_SO_CLOSE_AFTER_SEND, ( void * ) &xTrueValue, sizeof( xTrueValue ) ); - } - if( pcBuffer != pcFILE_BUFFER ) - { - pcBuffer = NULL; - } - xRc = FreeRTOS_send( pxClient->xTransferSocket, pcBuffer, uxCount, 0 ); - } - #endif /* ipconfigFTP_TX_ZERO_COPY */ - - if( xRc < 0 ) - { - break; - } - - pxClient->ulRecvBytes += xRc; - if( pxClient->uxBytesLeft == 0u ) - { - break; - } - } while( uxCount > 0u ); - - if( xRc < 0 ) - { - FreeRTOS_printf( ( "prvRetrieveFileWork: already disconnected\n" ) ); - } - else if( pxClient->uxBytesLeft <= 0u ) - { - BaseType_t x; - - for( x = 0; x < 5; x++ ) - { - xRc = FreeRTOS_recv( pxClient->xTransferSocket, pcFILE_BUFFER, sizeof( pcFILE_BUFFER ), 0 ); - if( xRc < 0 ) - { - break; - } - } -// FreeRTOS_printf( ( "prvRetrieveFileWork: %s all sent: xRc %ld\n", pxClient->pcFileName, xRc ) ); - } - else - { - FreeRTOS_FD_SET( pxClient->xTransferSocket, pxClient->pxParent->xSocketSet, eSELECT_WRITE ); - xSetEvent = pdTRUE; - } - if( xSetEvent == pdFALSE ) - { - FreeRTOS_FD_CLR( pxClient->xTransferSocket, pxClient->pxParent->xSocketSet, eSELECT_WRITE ); - } - return xRc; -} -/*-----------------------------------------------------------*/ - -/* -### ##### #### ##### - # # # # # # # - # # # # # - # # # # - # # ## # - # # # ## # - # # # # # # - # # # # # # -####### ##### #### #### -*/ -/* Prepare sending a directory LIST */ -static BaseType_t prvListSendPrep( FTPClient_t *pxClient ) -{ -BaseType_t xFindResult; -int iErrorNo; - - if( pxClient->bits1.bIsListen != pdFALSE_UNSIGNED ) - { - /* True if PASV is used */ - snprintf( pxClient->pcConnectionAck, sizeof( pxClient->pcConnectionAck ), - "150 Accepted data connection from %%xip:%%u\r\n" ); - } - else - { - BaseType_t xLength; - - /* Here the FTP server is supposed to connect() */ - xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), - "150 Opening ASCII mode data connection to for /bin/ls \r\n" ); - - prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength ); - /* Clear the current connection acknowledge message */ - pxClient->pcConnectionAck[ 0 ] = '\0'; - prvTransferStart( pxClient ); - } - - pxClient->xDirCount = 0; - xMakeAbsolute( pxClient, pcNEW_DIR, sizeof( pcNEW_DIR ), pxClient->pcCurrentDir ); - - xFindResult = ff_findfirst( pcNEW_DIR, &pxClient->xFindData ); - - pxClient->bits1.bDirHasEntry = ( xFindResult >= 0 ); - - iErrorNo = stdioGET_ERRNO(); - if( ( xFindResult < 0 ) && ( iErrorNo == pdFREERTOS_ERRNO_ENMFILE ) ) - { - FreeRTOS_printf( ("prvListSendPrep: Empty directory? (%s)\n", pxClient->pcCurrentDir ) ); - prvSendReply( pxClient->xTransferSocket, "total 0\r\n", 0 ); - pxClient->xDirCount++; - } - else if( xFindResult < 0 ) - { - FreeRTOS_printf( ( "prvListSendPrep: rc = %ld iErrorNo = %d\n", xFindResult, iErrorNo ) ); - prvSendReply( pxClient->xSocket, REPL_451, 0 ); - } - pxClient->pcClientAck[ 0 ] = '\0'; - - return pxClient->xDirCount; -} -/*-----------------------------------------------------------*/ - -#define MAX_DIR_LIST_ENTRY_SIZE 256 - -static BaseType_t prvListSendWork( FTPClient_t *pxClient ) -{ -BaseType_t xTxSpace; - - while( pxClient->bits1.bClientConnected != pdFALSE_UNSIGNED ) - { - char *pcWritePtr = pcCOMMAND_BUFFER; - BaseType_t xWriteLength; - - xTxSpace = FreeRTOS_tx_space( pxClient->xTransferSocket ); - - if( xTxSpace > ( BaseType_t ) sizeof( pcCOMMAND_BUFFER ) ) - { - xTxSpace = sizeof( pcCOMMAND_BUFFER ); - } - - while( ( xTxSpace >= MAX_DIR_LIST_ENTRY_SIZE ) && ( pxClient->bits1.bDirHasEntry != pdFALSE_UNSIGNED ) ) - { - BaseType_t xLength, xEndOfDir; - int32_t iRc; - int iErrorNo; - - xLength = prvGetFileInfoStat( &( pxClient->xFindData.xDirectoryEntry ), pcWritePtr, xTxSpace ); - - pxClient->xDirCount++; - pcWritePtr += xLength; - xTxSpace -= xLength; - - iRc = ff_findnext( &pxClient->xFindData ); - iErrorNo = stdioGET_ERRNO(); - - xEndOfDir = ( iRc < 0 ) && ( iErrorNo == pdFREERTOS_ERRNO_ENMFILE ); - - pxClient->bits1.bDirHasEntry = ( xEndOfDir == pdFALSE ) && ( iRc >= 0 ); - - if( ( iRc < 0 ) && ( xEndOfDir == pdFALSE ) ) - { - FreeRTOS_printf( ("prvListSendWork: %s (rc %08x)\n", - ( const char * ) strerror( iErrorNo ), - ( unsigned )iRc ) ); - } - } - xWriteLength = ( BaseType_t ) ( pcWritePtr - pcCOMMAND_BUFFER ); - - if( xWriteLength == 0 ) - { - break; - } - - if( pxClient->bits1.bDirHasEntry == pdFALSE_UNSIGNED ) - { - uint32_t ulTotalCount; - uint32_t ulFreeCount; - uint32_t ulPercentage; - - ulTotalCount = 1; - ulFreeCount = ff_diskfree( pxClient->pcCurrentDir, &ulTotalCount ); - ulPercentage = ( uint32_t ) ( ( 100ULL * ulFreeCount + ulTotalCount / 2 ) / ulTotalCount ); - - /* Prepare the ACK which will be sent when all data has been sent. */ - snprintf( pxClient->pcClientAck, sizeof( pxClient->pcClientAck ), - "226-Options: -l\r\n" - "226-%ld matches total\r\n" - "226 Total %lu KB (%lu %% free)\r\n", - pxClient->xDirCount, ulTotalCount /1024, ulPercentage ); - } - - if( xWriteLength ) - { - if( pxClient->bits1.bDirHasEntry == pdFALSE_UNSIGNED ) - { - BaseType_t xTrueValue = 1; - - FreeRTOS_setsockopt( pxClient->xTransferSocket, 0, FREERTOS_SO_CLOSE_AFTER_SEND, ( void * ) &xTrueValue, sizeof( xTrueValue ) ); - } - - prvSendReply( pxClient->xTransferSocket, pcCOMMAND_BUFFER, xWriteLength ); - } - - if( pxClient->bits1.bDirHasEntry == pdFALSE_UNSIGNED ) - { - prvSendReply( pxClient->xSocket, pxClient->pcClientAck, 0 ); - break; - } - - } /* while( pxClient->bits1.bClientConnected ) */ - - return 0; -} -/*-----------------------------------------------------------*/ - -static const char *pcMonthAbbrev( BaseType_t xMonth ) -{ -static const char pcMonthList[] = "JanFebMarAprMayJunJulAugSepOctNovDec"; - - if( xMonth < 1 || xMonth > 12 ) - xMonth = 12; - - return pcMonthList + 3 * ( xMonth - 1 ); -}; -/*-----------------------------------------------------------*/ - -static BaseType_t prvGetFileInfoStat( FF_DirEnt_t *pxEntry, char *pcLine, BaseType_t xMaxLength ) -{ - char date[ 16 ]; - char mode[ 11 ] = "----------"; - BaseType_t st_nlink = 1; - const char user[ 9 ] = "freertos"; - const char group[ 8 ] = "plusfat"; - -/* - * Creates a unix-style listing, understood by most FTP clients: - * - * -rw-rw-r-- 1 freertos FreeRTOS+FAT 10564588 Sep 01 00:17 03. Metaharmoniks - Star (Instrumental).mp3 - * -rw-rw-r-- 1 freertos FreeRTOS+FAT 19087839 Sep 01 00:17 04. Simon Le Grec - Dimitri (Wherever U Are) (Cosmos Mix).mp3 - * -rw-rw-r-- 1 freertos FreeRTOS+FAT 11100621 Sep 01 00:16 05. D-Chill - Mistake (feat. Katy Blue).mp3 - */ - - #if ( ffconfigTIME_SUPPORT == 1 ) - const FF_SystemTime_t *pxCreateTime = &( pxEntry->xCreateTime ); - #else - #warning Do not use this. - FF_SystemTime_t xCreateTime; - const FF_SystemTime_t *pxCreateTime = &xCreateTime; - #endif - size_t ulSize = ( size_t )pxEntry->ulFileSize; - const char *pcFileName = pxEntry->pcFileName; - - mode[ 0 ] = ( ( pxEntry->ucAttrib & FF_FAT_ATTR_DIR ) != 0 ) ? 'd' : '-'; - #if( ffconfigDEV_SUPPORT != 0 ) - { - if( ( pxEntry->ucAttrib & FF_FAT_ATTR_DIR ) == 0 ) - { - switch( pxEntry->ucIsDeviceDir ) - { - case FF_DEV_CHAR_DEV: - mode[ 0 ] = 'c'; - break; - case FF_DEV_BLOCK_DEV: - mode[ 0 ] = 'b'; - break; - } - } - } - #endif /* ffconfigDEV_SUPPORT != 0 */ - - mode[ 1 ] = 'r'; /* Owner. */ - mode[ 2 ] = ( ( pxEntry->ucAttrib & FF_FAT_ATTR_READONLY ) != 0 ) ? '-' : 'w'; - mode[ 3 ] = '-'; /* x for executable. */ - - mode[ 4 ] = 'r'; /* group. */ - mode[ 5 ] = ( ( pxEntry->ucAttrib & FF_FAT_ATTR_READONLY ) != 0 ) ? '-' : 'w'; - mode[ 6 ] = '-'; /* x for executable. */ - - mode[ 7 ] = 'r'; /* world. */ - mode[ 8 ] = '-'; - mode[ 9 ] = '-'; /* x for executable. */ - - if( pxCreateTime->Month && pxCreateTime->Day ) - { - snprintf( date, sizeof( date ), "%-3.3s %02d %02d:%02d", - pcMonthAbbrev( pxCreateTime->Month ), - pxCreateTime->Day, - pxCreateTime->Hour, - pxCreateTime->Minute ); - } - else - { - snprintf (date, sizeof( date ), "Jan 01 1970"); - } - return snprintf( pcLine, xMaxLength, "%s %3ld %-4s %-4s %8d %12s %s\r\n", - mode, st_nlink, user, group, ( int ) ulSize, date, pcFileName ); -} -/*-----------------------------------------------------------*/ - -/* - #### # # ##### - # # # # # # -# # # # # # -# # # # # # -# # # # # # -# # # # # # -# # ## ## # # - # # ## ## # # - #### ## ## ##### -*/ -static BaseType_t prvChangeDir( FTPClient_t *pxClient, char *pcDirectory ) -{ -BaseType_t xResult; -BaseType_t xIsRootDir, xLength, xValid; -BaseType_t xIsDotDir = 0; - - if( pcDirectory[ 0 ] == '.' ) - { - if( ( pcDirectory[ 1 ] == '.' ) && - ( pcDirectory[ 2 ] == '\0' ) ) - { - xIsDotDir = 2; - } - else if( pcDirectory[ 1 ] == '\0' ) - { - xIsDotDir = 1; - } - } - - if( xIsDotDir != 0 ) - { - strcpy( pcFILE_BUFFER, pxClient->pcCurrentDir ); - - if( pcDirectory[ 1 ] == '.' ) - { - char *p = strrchr( pcFILE_BUFFER, '/' ); - if( p != NULL ) - { - if( p == pcFILE_BUFFER ) - { - p[ 1 ] = '\0'; - } - else - { - p[ 0 ] = '\0'; - } - } - } - } - else - { - if(pcDirectory[ 0 ] != '/' ) - { - BaseType_t xCurLength; - - xCurLength = strlen( pxClient->pcCurrentDir ); - snprintf( pcFILE_BUFFER, sizeof( pcFILE_BUFFER ), "%s%s%s", - pxClient->pcCurrentDir, - pxClient->pcCurrentDir[ xCurLength - 1 ] == '/' ? "" : "/", - pcDirectory ); - } - else - { - snprintf( pcFILE_BUFFER, sizeof( pcFILE_BUFFER ), "%s", pcDirectory ); - } - } - - xIsRootDir = ( pcFILE_BUFFER[ 0 ] == '/' ) && ( pcFILE_BUFFER[ 1 ] == '\0' ); - xMakeAbsolute( pxClient, pcNEW_DIR, sizeof( pcNEW_DIR ), pcFILE_BUFFER ); - - if( ( ( xIsRootDir == pdFALSE ) || ( FF_FS_Count() == 0 ) ) && ( ff_finddir( pcNEW_DIR ) == pdFALSE ) ) - { - xValid = pdFALSE; - } - else - { - xValid = pdTRUE; - } - - if( xValid == pdFALSE ) - { - /* Get the directory cluster, if it exists. */ - FreeRTOS_printf( ("FTP: chdir \"%s\": No such dir\n", pcNEW_DIR ) ); - //#define REPL_550 "550 Requested action not taken.\r\n" - //550 /home/hein/arch/h8300: No such file or directory - xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), - "550 %s: No such file or directory\r\n", - pcNEW_DIR ); - prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength ); - xResult = pdFALSE; - } - else - { - memcpy( pxClient->pcCurrentDir, pcNEW_DIR, sizeof( pxClient->pcCurrentDir ) ); - - xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), "250 Changed to %s\r\n", pcNEW_DIR ); - prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength ); - xResult = pdTRUE; - } - - return xResult; -} -/*-----------------------------------------------------------*/ - -/* -###### ## # ####### ###### - # # ## # # ## # # - # # ## # # # # # - # # ### # # # # # - ###### # ## # ##### ###### - # ## # ## # # # # ## - # # # ### # # # - # # # ## # # # -### ## # ## #### ### ## -*/ -static BaseType_t prvRenameFrom( FTPClient_t *pxClient, const char *pcFileName ) -{ -const char *myReply; -FF_FILE *fh; - - xMakeAbsolute( pxClient, pxClient->pcFileName, sizeof( pxClient->pcFileName ), pcFileName ); - - myReply = NULL; - - fh = ff_fopen( pxClient->pcFileName, "rb" ); - - if( fh != NULL ) - { - ff_fclose( fh ); - /* REPL_350; "350 Requested file action pending further information." */ - snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), - "350 Rename '%s' ...\r\n", pxClient->pcFileName ); - myReply = pcCOMMAND_BUFFER; - pxClient->bits.bInRename = pdTRUE_UNSIGNED; - } - else if( stdioGET_ERRNO() == pdFREERTOS_ERRNO_EISDIR ) - { - snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), - "350 Rename directory '%s' ...\r\n", pxClient->pcFileName ); - myReply = pcCOMMAND_BUFFER; - pxClient->bits.bInRename = pdTRUE_UNSIGNED; - } - else - { - FreeRTOS_printf( ("ftp::renameFrom[%s]\n%s\n", pxClient->pcFileName, strerror( stdioGET_ERRNO() ) ) ); - myReply = REPL_451; /* "451 Requested action aborted. Local error in processing." */ - } - if( myReply ) - { - prvSendReply( pxClient->xSocket, myReply, 0 ); - } - - return pdTRUE; -} -/*-----------------------------------------------------------*/ - -/* -###### ## # ##### ### - # # ## # # # # ## ## - # # ## # # ## ## - # # ### # # # # - ###### # ## # # # # - # ## # ## # # # # - # # # ### # ## ## - # # # ## # ## ## -### ## # ## #### ### -*/ -static BaseType_t prvRenameTo( FTPClient_t *pxClient, const char *pcFileName ) -{ -const char *myReply = NULL; -int iResult; - - xMakeAbsolute( pxClient, pcNEW_DIR, sizeof( pcNEW_DIR ), pcFileName ); - - /* FreeRTOS+FAT rename has an extra parameter: "remove target if already - exists". */ - iResult = ff_rename( pxClient->pcFileName, pcNEW_DIR, pdFALSE ); - - if( iResult < 0 ) - { - iResult = stdioGET_ERRNO(); - } - else - { - iResult = 0; - } - - switch( iResult ) - { - case 0: - FreeRTOS_printf( ( "ftp::renameTo[%s,%s]: Ok\n", pxClient->pcFileName, pcNEW_DIR ) ); - snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), - "250 Rename successful to '%s'\r\n", pcNEW_DIR ); - myReply = pcCOMMAND_BUFFER; - break; - case pdFREERTOS_ERRNO_EEXIST: - /* the destination file already exists. - "450 Requested file action not taken.\r\n"*/ - snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), - "450 Already exists '%s'\r\n", pcNEW_DIR ); - myReply = pcCOMMAND_BUFFER; - break; - case pdFREERTOS_ERRNO_EIO: /* FF_ERR_FILE_COULD_NOT_CREATE_DIRENT */ - /* if dirent creation failed (fatal error!). - "553 Requested action not taken.\r\n" */ - FreeRTOS_printf( ("ftp::renameTo[%s,%s]: Error creating DirEnt\n", - pxClient->pcFileName, pcNEW_DIR ) ); - myReply = REPL_553; - break; - case pdFREERTOS_ERRNO_ENXIO: - case pdFREERTOS_ERRNO_ENOENT: - /* if the source file was not found. - "450 Requested file action not taken.\r\n" */ - snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), - "450 No such file '%s'\r\n", pxClient->pcFileName ); - myReply = pcCOMMAND_BUFFER; - break; - default: - FreeRTOS_printf( ("ftp::renameTo[%s,%s]: %s\n", pxClient->pcFileName, pcNEW_DIR, - (const char*)strerror( stdioGET_ERRNO() ) ) ); - myReply = REPL_451; /* "451 Requested action aborted. Local error in processing." */ - break; - } - prvSendReply( pxClient->xSocket, myReply, 0 ); - - return pdTRUE; -} -/*-----------------------------------------------------------*/ - -/* - #### # -# # # # -# # # -# ### ###### #### - ## # # # # - ## # # ###### -# # # # # -# # # # ## # ## - #### ##### ## #### -*/ -static BaseType_t prvSiteCmd( FTPClient_t *pxClient, char *pcRestCommand ) -{ - ( void ) pxClient; - ( void ) pcRestCommand; - - return 0; -} -/*-----------------------------------------------------------*/ - -/* -##### ### - # # # # - # # # # - # # #### # #### ###### #### - # # # # # # # # # # - # # ###### # ###### # ###### - # # # # # # # - # # # ## # # ## # ## # ## -##### #### ##### #### ## #### -*/ -static BaseType_t prvDeleteFile( FTPClient_t *pxClient, char *pcFileName ) -{ -BaseType_t xResult, xLength; -int32_t iRc; -int iErrorNo; - - /* DELE: Delete a file. */ - xMakeAbsolute( pxClient, pxClient->pcFileName, sizeof( pxClient->pcFileName ), pcFileName ); - - iRc = ff_remove( pxClient->pcFileName ); - - if (iRc >= 0 ) - { - xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), - "250 File \"%s\" removed\r\n", pxClient->pcFileName ); - xResult = pdTRUE; - } - else - { - const char *errMsg = "other error"; - - iErrorNo = stdioGET_ERRNO(); - switch( iErrorNo ) - { /*_RB_ What do these negative numbers relate to? */ - case pdFREERTOS_ERRNO_ENOENT: errMsg = "No such file"; break; /* -31 File was not found. */ - case pdFREERTOS_ERRNO_EALREADY: errMsg = "File still open"; break; /* -30 File is in use. */ - case pdFREERTOS_ERRNO_EISDIR: errMsg = "Is a dir"; break; /* -32 Tried to FF_Open() a Directory. */ - case pdFREERTOS_ERRNO_EROFS: errMsg = "Read-only"; break; /* -33 Tried to FF_Open() a file marked read only. */ - case pdFREERTOS_ERRNO_ENOTDIR: errMsg = "Invalid path"; break; /* -34 The path of the file was not found. */ - } - FreeRTOS_printf( ( "ftp::delFile: '%s' because %s\n", - pxClient->pcFileName, strerror( iErrorNo ) ) ); - - xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), - "521-\"%s\" %s;\r\n" - "521 taking no action\r\n", - pxClient->pcFileName, errMsg ); - - xResult = pdFALSE; - } - - prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength ); - - return xResult; -} -/*-----------------------------------------------------------*/ - -/* - #### # ##### -# # # # # # -# # # # # -# ### ###### #### # # #### ###### #### - ## # # # # # # # # # # # - ## # # ###### # # ##### # ###### -# # # # # # # # # # # -# # # # # ## # # # # # ## # ## - #### ##### ###### #### ##### ### ## ## #### -*/ -static BaseType_t prvSizeDateFile( FTPClient_t *pxClient, char *pcFileName, BaseType_t xSendDate ) -{ -BaseType_t xResult = pdFALSE; -char *pcPtr; - - /* SIZE: get the size of a file (xSendDate = 0) - MDTM: get data and time properties (xSendDate = 1) */ - xMakeAbsolute( pxClient, pxClient->pcFileName, sizeof( pxClient->pcFileName ), pcFileName ); - - pcPtr = strrchr( pxClient->pcFileName, '/' ); - - if( ( pcPtr != NULL ) && ( pcPtr[ 1 ] != '\0' ) ) - { - FF_Stat_t xStatBuf; - int32_t iRc = ff_stat( pxClient->pcFileName, &xStatBuf ); - if (iRc < 0 ) - FreeRTOS_printf( ("In %s: %s\n", pxClient->pcFileName, - ( const char* )strerror( stdioGET_ERRNO() ) ) ); - - if( iRc == 0 ) - { - BaseType_t xLength; - /* "YYYYMMDDhhmmss" */ - if( xSendDate != pdFALSE ) - { - #if( ffconfigTIME_SUPPORT != 0 ) - { - FF_TimeStruct_t tmStruct; - time_t secs = xStatBuf.st_mtime; - FreeRTOS_gmtime_r( &secs, &tmStruct ); - - xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), "213 %04u%02u%02u%02u%02u%02u\r\n", - tmStruct.tm_year + 1900, - tmStruct.tm_mon+1, - tmStruct.tm_mday, - tmStruct.tm_hour, - tmStruct.tm_min, - tmStruct.tm_sec ); - } - #else - { - xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), "213 19700101000000\r\n", - } - #endif - } - else - { - xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), "213 %lu\r\n", xStatBuf.st_size ); - } - prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength ); - xResult = pdTRUE; - } - else - { - FreeRTOS_printf( ("ftp::sizeDateFile: No such file %s\n", pxClient->pcFileName ) ); - } - } else { - FreeRTOS_printf( ("ftp::sizeDateFile: Invalid file name: %s ?\n", pxClient->pcFileName ) ); - } - if( xResult == pdFALSE ) - { - prvSendReply( pxClient->xSocket, REPL_450, 0 ); /* "Requested file action not taken". */ - } - - return xResult; -} -/*-----------------------------------------------------------*/ - -/* -## ## ## ## ##### ###### ## ## ##### -### ### # # # # # # ### ### # # -# ### # # # # # # # # ### # # # -# # # # # # # # # # # # # # -# # # #### # # ###### # # # # # -# # # # # # # ## # # # # -# # # # # # # # # # # # -# # # # # # # # # # # # -# # ### ## ##### ### ## # # ##### -*/ -static BaseType_t prvMakeRemoveDir( FTPClient_t *pxClient, const char *pcDirectory, BaseType_t xDoRemove ) -{ -BaseType_t xResult; -BaseType_t xLength; -int32_t iRc; -int iErrorNo; - - /* MKD: Make / create a directory (xDoRemove = 0) - RMD: Remove a directory (xDoRemove = 1) */ - xMakeAbsolute( pxClient, pxClient->pcFileName, sizeof( pxClient->pcFileName ), pcDirectory ); - - if( xDoRemove ) - { - iRc = ff_rmdir( pxClient->pcFileName ); - } - else - { - #if( ffconfigMKDIR_RECURSIVE != 0 ) - { - iRc = ff_mkdir( pxClient->pcFileName, pdFALSE ); - } - #else - { - iRc = ff_mkdir( pxClient->pcFileName ); - } - #endif /* ffconfigMKDIR_RECURSIVE */ - } - xResult = pdTRUE; - - if( iRc >= 0 ) - { - xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), "257 \"%s\" directory %s\r\n", - pxClient->pcFileName, xDoRemove ? "removed" : "created" ); - } - else - { - const char *errMsg = "other error"; - BaseType_t xFTPCode = 521; - - xResult = pdFALSE; - iErrorNo = stdioGET_ERRNO(); - switch( iErrorNo ) - { - case pdFREERTOS_ERRNO_EEXIST: errMsg = "Directory already exists"; break; - case pdFREERTOS_ERRNO_ENOTDIR: errMsg = "Invalid path"; break; /* -34 The path of the file was not found. *//*_RB_ As before, what do these negative numbers relate to? */ - case pdFREERTOS_ERRNO_ENOTEMPTY:errMsg = "Dir not empty"; break; - case pdFREERTOS_ERRNO_EROFS: errMsg = "Read-only"; break; /* -33 Tried to FF_Open() a file marked read only. */ - default: errMsg = strerror( iErrorNo ); break; - } - if( iErrorNo == pdFREERTOS_ERRNO_ENOSPC ) - { - xFTPCode = 552; - } - xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), - "%ld-\"%s\" %s;\r\n" - "%ld taking no action\r\n", - xFTPCode, pxClient->pcFileName, errMsg, xFTPCode ); - FreeRTOS_printf( ( "%sdir '%s': %s\n", xDoRemove ? "rm" : "mk", pxClient->pcFileName, errMsg ) ); - } - prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength ); - - return xResult; -} -/*-----------------------------------------------------------*/ - -static portINLINE BaseType_t IsDigit( char cChar ) -{ -BaseType_t xResult; - - if( cChar >= '0' && cChar <= '9' ) - { - xResult = pdTRUE; - } - else - { - xResult = pdFALSE; - } - return xResult; -} - -static BaseType_t prvSendReply( Socket_t xSocket, const char *pcBuffer, BaseType_t xLength ) -{ -BaseType_t xResult; - - if( xLength == 0 ) - { - xLength = strlen( pcBuffer ); - } - xResult = FreeRTOS_send( xSocket, ( const void * )pcBuffer, ( size_t ) xLength, 0 ); - if( IsDigit( ( int ) pcBuffer[ 0 ] ) && - IsDigit( ( int ) pcBuffer[ 1 ] ) && - IsDigit( ( int ) pcBuffer[ 2 ] ) && - IsDigit( ( int ) pcBuffer[ 3 ] ) ) - { - const char *last = pcBuffer + strlen( pcBuffer ); - int iLength; - while( ( last > pcBuffer ) && ( ( last[ -1 ] == ftpASCII_CR ) || ( last[ -1 ] == ftpASCII_LF ) ) ) - { - last--; - } - iLength = ( int )( last - pcBuffer ); - FF_PRINTF( " %-*.*s", iLength, iLength, pcBuffer ); - } - return xResult; -} -/*-----------------------------------------------------------*/ - -#if( ipconfigFTP_HAS_RECEIVED_HOOK != 0 ) - - /* - * The following function is called for every file received: - * void vApplicationFTPReceivedHook( pcFileName, ulSize, pxFTPClient ); - * This callback function may do a callback to vFTPReplyMessage() to send messages - * to the FTP client like: - * 200-Please wait: Received new firmware - * 200-Please wait: Please wait a few seconds for reboot - */ - void vFTPReplyMessage( struct xFTP_CLIENT *pxFTPClient, const char *pcMessage ) - { - if( ( pxFTPClient != NULL ) && ( pxFTPClient->xSocket != NULL ) ) - { - prvSendReply( pxFTPClient->xSocket, pcMessage, 0 ); - } - } - /*-----------------------------------------------------------*/ - -#endif /* ipconfigFTP_HAS_RECEIVED_HOOK != 0 */ - -/* - * Some explanation: - * The FTP client may send: "DELE readme.txt" - * Here the complete path is constructed consisting of 3 parts: - * - * pxClient->pcRootDir + pxClient->pcCurrentDir + pcFileName - * - * 'pcCurrentDir' will not be applied for an absolute path like in "DELE /.htaccess" - */ -BaseType_t xMakeAbsolute( FTPClient_t *pxClient, char *pcBuffer, BaseType_t xBufferLength, const char *pcFileName ) -{ -BaseType_t xLength = strlen( pxClient->pcRootDir ); - - if( pcFileName[ 0 ] != '/' ) - { - char *pcNewDirBuffer = pcNEW_DIR; - BaseType_t xCurLength; - - xCurLength = strlen( pxClient->pcCurrentDir ); - if( pcBuffer == pcNEW_DIR ) - { - /* In one call, the result already goes into pcNEW_DIR. - Use pcFILE_BUFFER in that case */ - pcNewDirBuffer = pcFILE_BUFFER; - } - snprintf( pcNewDirBuffer, sizeof( pcNEW_DIR ), "%s%s%s", - pxClient->pcCurrentDir, - pxClient->pcCurrentDir[ xCurLength - 1 ] == '/' ? "" : "/", - pcFileName ); - pcFileName = pcNewDirBuffer; - } - if( strncasecmp( pxClient->pcRootDir, pcFileName, xLength ) == 0 ) - { - xLength = snprintf( pcBuffer, xBufferLength, "%s", pcFileName ); - } - else - { - xLength = snprintf( pcBuffer, xBufferLength, "%s/%s", - pxClient->pcRootDir, - pcFileName[ 0 ] == '/' ? ( pcFileName + 1 ) : pcFileName ); - } - - #if( ipconfigFTP_FS_USES_BACKSLAH == 1 ) - for( pcPtr = pcBuffer; *pcPtr; pcPtr++ ) - { - if( pcPtr[ 0 ] == '/' ) - { - pcPtr[ 0 ] = '\\'; - } - } - #endif - - return xLength; -} -/*-----------------------------------------------------------*/ - -BaseType_t xMakeRelative( FTPClient_t *pxClient, char *pcBuffer, BaseType_t xBufferLength, const char *pcFileName ) -{ -BaseType_t xLength = strlen( pxClient->pcRootDir ); - - if( strncasecmp ( pxClient->pcRootDir, pcFileName, xLength ) == 0 ) - { - xLength = snprintf( pcBuffer, xBufferLength, "%s", pcFileName + xLength ); - } - else - { - xLength = snprintf( pcBuffer, xBufferLength, "%s", pcFileName ); - } - - return xLength; -} -/*-----------------------------------------------------------*/ - -#endif /* ipconfigUSE_FTP */ - - - diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/HTTP/FreeRTOS_HTTP_commands.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/HTTP/FreeRTOS_HTTP_commands.c deleted file mode 100644 index f8b5ac250..000000000 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/HTTP/FreeRTOS_HTTP_commands.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * FreeRTOS+TCP V2.0.3 - * 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 - */ - - -/* Standard includes. */ -#include -#include - -/* FreeRTOS includes. */ -#include "FreeRTOS.h" - -#include "FreeRTOS_HTTP_commands.h" - -const struct xWEB_COMMAND xWebCommands[ WEB_CMD_COUNT ] = -{ - { 3, "GET", ECMD_GET }, - { 4, "HEAD", ECMD_HEAD }, - { 4, "POST", ECMD_POST }, - { 3, "PUT", ECMD_PUT }, - { 6, "DELETE", ECMD_DELETE }, - { 5, "TRACE", ECMD_TRACE }, - { 7, "OPTIONS", ECMD_OPTIONS }, - { 7, "CONNECT", ECMD_CONNECT }, - { 5, "PATCH", ECMD_PATCH }, - { 4, "UNKN", ECMD_UNK }, -}; - -const char *webCodename (int aCode) -{ - switch (aCode) { - case WEB_REPLY_OK: // = 200, - return "OK"; - case WEB_NO_CONTENT: // 204 - return "No content"; - case WEB_BAD_REQUEST: // = 400, - return "Bad request"; - case WEB_UNAUTHORIZED: // = 401, - return "Authorization Required"; - case WEB_NOT_FOUND: // = 404, - return "Not Found"; - case WEB_GONE: // = 410, - return "Done"; - case WEB_PRECONDITION_FAILED: // = 412, - return "Precondition Failed"; - case WEB_INTERNAL_SERVER_ERROR: // = 500, - return "Internal Server Error"; - } - return "Unknown"; -} diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/HTTP/FreeRTOS_HTTP_server.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/HTTP/FreeRTOS_HTTP_server.c deleted file mode 100644 index ee69fd11e..000000000 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/HTTP/FreeRTOS_HTTP_server.c +++ /dev/null @@ -1,428 +0,0 @@ -/* - * FreeRTOS+TCP V2.0.3 - * 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 - */ - -/* Standard includes. */ -#include -#include - -/* FreeRTOS includes. */ -#include "FreeRTOS.h" -#include "task.h" - -/* FreeRTOS+TCP includes. */ -#include "FreeRTOS_IP.h" -#include "FreeRTOS_Sockets.h" - -/* FreeRTOS Protocol includes. */ -#include "FreeRTOS_HTTP_commands.h" -#include "FreeRTOS_TCP_server.h" -#include "FreeRTOS_server_private.h" - -/* Remove the whole file if HTTP is not supported. */ -#if( ipconfigUSE_HTTP == 1 ) - -/* FreeRTOS+FAT includes. */ -#include "ff_stdio.h" - -#ifndef HTTP_SERVER_BACKLOG - #define HTTP_SERVER_BACKLOG ( 12 ) -#endif - -#ifndef USE_HTML_CHUNKS - #define USE_HTML_CHUNKS ( 0 ) -#endif - -#if !defined( ARRAY_SIZE ) - #define ARRAY_SIZE(x) ( BaseType_t ) (sizeof( x ) / sizeof( x )[ 0 ] ) -#endif - -/* Some defines to make the code more readbale */ -#define pcCOMMAND_BUFFER pxClient->pxParent->pcCommandBuffer -#define pcNEW_DIR pxClient->pxParent->pcNewDir -#define pcFILE_BUFFER pxClient->pxParent->pcFileBuffer - -#ifndef ipconfigHTTP_REQUEST_CHARACTER - #define ipconfigHTTP_REQUEST_CHARACTER '?' -#endif - -/*_RB_ Need comment block, although fairly self evident. */ -static void prvFileClose( HTTPClient_t *pxClient ); -static BaseType_t prvProcessCmd( HTTPClient_t *pxClient, BaseType_t xIndex ); -static const char *pcGetContentsType( const char *apFname ); -static BaseType_t prvOpenURL( HTTPClient_t *pxClient ); -static BaseType_t prvSendFile( HTTPClient_t *pxClient ); -static BaseType_t prvSendReply( HTTPClient_t *pxClient, BaseType_t xCode ); - -static const char pcEmptyString[1] = { '\0' }; - -typedef struct xTYPE_COUPLE -{ - const char *pcExtension; - const char *pcType; -} TypeCouple_t; - -static TypeCouple_t pxTypeCouples[ ] = -{ - { "html", "text/html" }, - { "css", "text/css" }, - { "js", "text/javascript" }, - { "png", "image/png" }, - { "jpg", "image/jpeg" }, - { "gif", "image/gif" }, - { "txt", "text/plain" }, - { "mp3", "audio/mpeg3" }, - { "wav", "audio/wav" }, - { "flac", "audio/ogg" }, - { "pdf", "application/pdf" }, - { "ttf", "application/x-font-ttf" }, - { "ttc", "application/x-font-ttf" } -}; - -void vHTTPClientDelete( TCPClient_t *pxTCPClient ) -{ -HTTPClient_t *pxClient = ( HTTPClient_t * ) pxTCPClient; - - /* This HTTP client stops, close / release all resources. */ - if( pxClient->xSocket != FREERTOS_NO_SOCKET ) - { - FreeRTOS_FD_CLR( pxClient->xSocket, pxClient->pxParent->xSocketSet, eSELECT_ALL ); - FreeRTOS_closesocket( pxClient->xSocket ); - pxClient->xSocket = FREERTOS_NO_SOCKET; - } - prvFileClose( pxClient ); -} -/*-----------------------------------------------------------*/ - -static void prvFileClose( HTTPClient_t *pxClient ) -{ - if( pxClient->pxFileHandle != NULL ) - { - FreeRTOS_printf( ( "Closing file: %s\n", pxClient->pcCurrentFilename ) ); - ff_fclose( pxClient->pxFileHandle ); - pxClient->pxFileHandle = NULL; - } -} -/*-----------------------------------------------------------*/ - -static BaseType_t prvSendReply( HTTPClient_t *pxClient, BaseType_t xCode ) -{ -struct xTCP_SERVER *pxParent = pxClient->pxParent; -BaseType_t xRc; - - /* A normal command reply on the main socket (port 21). */ - char *pcBuffer = pxParent->pcFileBuffer; - - xRc = snprintf( pcBuffer, sizeof( pxParent->pcFileBuffer ), - "HTTP/1.1 %d %s\r\n" -#if USE_HTML_CHUNKS - "Transfer-Encoding: chunked\r\n" -#endif - "Content-Type: %s\r\n" - "Connection: keep-alive\r\n" - "%s\r\n", - ( int ) xCode, - webCodename (xCode), - pxParent->pcContentsType[0] ? pxParent->pcContentsType : "text/html", - pxParent->pcExtraContents ); - - pxParent->pcContentsType[0] = '\0'; - pxParent->pcExtraContents[0] = '\0'; - - xRc = FreeRTOS_send( pxClient->xSocket, ( const void * ) pcBuffer, xRc, 0 ); - pxClient->bits.bReplySent = pdTRUE_UNSIGNED; - - return xRc; -} -/*-----------------------------------------------------------*/ - -static BaseType_t prvSendFile( HTTPClient_t *pxClient ) -{ -size_t uxSpace; -size_t uxCount; -BaseType_t xRc = 0; - - if( pxClient->bits.bReplySent == pdFALSE_UNSIGNED ) - { - pxClient->bits.bReplySent = pdTRUE_UNSIGNED; - - strcpy( pxClient->pxParent->pcContentsType, pcGetContentsType( pxClient->pcCurrentFilename ) ); - snprintf( pxClient->pxParent->pcExtraContents, sizeof( pxClient->pxParent->pcExtraContents ), - "Content-Length: %d\r\n", ( int ) pxClient->uxBytesLeft ); - - /* "Requested file action OK". */ - xRc = prvSendReply( pxClient, WEB_REPLY_OK ); - } - - if( xRc >= 0 ) do - { - uxSpace = FreeRTOS_tx_space( pxClient->xSocket ); - - if( pxClient->uxBytesLeft < uxSpace ) - { - uxCount = pxClient->uxBytesLeft; - } - else - { - uxCount = uxSpace; - } - - if( uxCount > 0u ) - { - if( uxCount > sizeof( pxClient->pxParent->pcFileBuffer ) ) - { - uxCount = sizeof( pxClient->pxParent->pcFileBuffer ); - } - ff_fread( pxClient->pxParent->pcFileBuffer, 1, uxCount, pxClient->pxFileHandle ); - pxClient->uxBytesLeft -= uxCount; - - xRc = FreeRTOS_send( pxClient->xSocket, pxClient->pxParent->pcFileBuffer, uxCount, 0 ); - if( xRc < 0 ) - { - break; - } - } - } while( uxCount > 0u ); - - if( pxClient->uxBytesLeft == 0u ) - { - /* Writing is ready, no need for further 'eSELECT_WRITE' events. */ - FreeRTOS_FD_CLR( pxClient->xSocket, pxClient->pxParent->xSocketSet, eSELECT_WRITE ); - prvFileClose( pxClient ); - } - else - { - /* Wake up the TCP task as soon as this socket may be written to. */ - FreeRTOS_FD_SET( pxClient->xSocket, pxClient->pxParent->xSocketSet, eSELECT_WRITE ); - } - - return xRc; -} -/*-----------------------------------------------------------*/ - -static BaseType_t prvOpenURL( HTTPClient_t *pxClient ) -{ -BaseType_t xRc; -char pcSlash[ 2 ]; - - pxClient->bits.ulFlags = 0; - - #if( ipconfigHTTP_HAS_HANDLE_REQUEST_HOOK != 0 ) - { - if( strchr( pxClient->pcUrlData, ipconfigHTTP_REQUEST_CHARACTER ) != NULL ) - { - size_t xResult; - - xResult = uxApplicationHTTPHandleRequestHook( pxClient->pcUrlData, pxClient->pcCurrentFilename, sizeof( pxClient->pcCurrentFilename ) ); - if( xResult > 0 ) - { - strcpy( pxClient->pxParent->pcContentsType, "text/html" ); - snprintf( pxClient->pxParent->pcExtraContents, sizeof( pxClient->pxParent->pcExtraContents ), - "Content-Length: %d\r\n", ( int ) xResult ); - xRc = prvSendReply( pxClient, WEB_REPLY_OK ); /* "Requested file action OK" */ - if( xRc > 0 ) - { - xRc = FreeRTOS_send( pxClient->xSocket, pxClient->pcCurrentFilename, xResult, 0 ); - } - /* Although against the coding standard of FreeRTOS, a return is - done here to simplify this conditional code. */ - return xRc; - } - } - } - #endif /* ipconfigHTTP_HAS_HANDLE_REQUEST_HOOK */ - - if( pxClient->pcUrlData[ 0 ] != '/' ) - { - /* Insert a slash before the file name. */ - pcSlash[ 0 ] = '/'; - pcSlash[ 1 ] = '\0'; - } - else - { - /* The browser provided a starting '/' already. */ - pcSlash[ 0 ] = '\0'; - } - snprintf( pxClient->pcCurrentFilename, sizeof( pxClient->pcCurrentFilename ), "%s%s%s", - pxClient->pcRootDir, - pcSlash, - pxClient->pcUrlData); - - pxClient->pxFileHandle = ff_fopen( pxClient->pcCurrentFilename, "rb" ); - - FreeRTOS_printf( ( "Open file '%s': %s\n", pxClient->pcCurrentFilename, - pxClient->pxFileHandle != NULL ? "Ok" : strerror( stdioGET_ERRNO() ) ) ); - - if( pxClient->pxFileHandle == NULL ) - { - /* "404 File not found". */ - xRc = prvSendReply( pxClient, WEB_NOT_FOUND ); - } - else - { - pxClient->uxBytesLeft = ( size_t ) pxClient->pxFileHandle->ulFileSize; - xRc = prvSendFile( pxClient ); - } - - return xRc; -} -/*-----------------------------------------------------------*/ - -static BaseType_t prvProcessCmd( HTTPClient_t *pxClient, BaseType_t xIndex ) -{ -BaseType_t xResult = 0; - - /* A new command has been received. Process it. */ - switch( xIndex ) - { - case ECMD_GET: - xResult = prvOpenURL( pxClient ); - break; - - case ECMD_HEAD: - case ECMD_POST: - case ECMD_PUT: - case ECMD_DELETE: - case ECMD_TRACE: - case ECMD_OPTIONS: - case ECMD_CONNECT: - case ECMD_PATCH: - case ECMD_UNK: - { - FreeRTOS_printf( ( "prvProcessCmd: Not implemented: %s\n", - xWebCommands[xIndex].pcCommandName ) ); - } - break; - } - - return xResult; -} -/*-----------------------------------------------------------*/ - -BaseType_t xHTTPClientWork( TCPClient_t *pxTCPClient ) -{ -BaseType_t xRc; -HTTPClient_t *pxClient = ( HTTPClient_t * ) pxTCPClient; - - if( pxClient->pxFileHandle != NULL ) - { - prvSendFile( pxClient ); - } - - xRc = FreeRTOS_recv( pxClient->xSocket, ( void * )pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), 0 ); - - if( xRc > 0 ) - { - BaseType_t xIndex; - const char *pcEndOfCmd; - const struct xWEB_COMMAND *curCmd; - char *pcBuffer = pcCOMMAND_BUFFER; - - if( xRc < ( BaseType_t ) sizeof( pcCOMMAND_BUFFER ) ) - { - pcBuffer[ xRc ] = '\0'; - } - while( xRc && ( pcBuffer[ xRc - 1 ] == 13 || pcBuffer[ xRc - 1 ] == 10 ) ) - { - pcBuffer[ --xRc ] = '\0'; - } - pcEndOfCmd = pcBuffer + xRc; - - curCmd = xWebCommands; - - /* Pointing to "/index.html HTTP/1.1". */ - pxClient->pcUrlData = pcBuffer; - - /* Pointing to "HTTP/1.1". */ - pxClient->pcRestData = pcEmptyString; - - /* Last entry is "ECMD_UNK". */ - for( xIndex = 0; xIndex < WEB_CMD_COUNT - 1; xIndex++, curCmd++ ) - { - BaseType_t xLength; - - xLength = curCmd->xCommandLength; - if( ( xRc >= xLength ) && ( memcmp( curCmd->pcCommandName, pcBuffer, xLength ) == 0 ) ) - { - char *pcLastPtr; - - pxClient->pcUrlData += xLength + 1; - for( pcLastPtr = (char *)pxClient->pcUrlData; pcLastPtr < pcEndOfCmd; pcLastPtr++ ) - { - char ch = *pcLastPtr; - if( ( ch == '\0' ) || ( strchr( "\n\r \t", ch ) != NULL ) ) - { - *pcLastPtr = '\0'; - pxClient->pcRestData = pcLastPtr + 1; - break; - } - } - break; - } - } - - if( xIndex < ( WEB_CMD_COUNT - 1 ) ) - { - xRc = prvProcessCmd( pxClient, xIndex ); - } - } - else if( xRc < 0 ) - { - /* The connection will be closed and the client will be deleted. */ - FreeRTOS_printf( ( "xHTTPClientWork: rc = %ld\n", xRc ) ); - } - return xRc; -} -/*-----------------------------------------------------------*/ - -static const char *pcGetContentsType (const char *apFname) -{ - const char *slash = NULL; - const char *dot = NULL; - const char *ptr; - const char *pcResult = "text/html"; - BaseType_t x; - - for( ptr = apFname; *ptr; ptr++ ) - { - if (*ptr == '.') dot = ptr; - if (*ptr == '/') slash = ptr; - } - if( dot > slash ) - { - dot++; - for( x = 0; x < ARRAY_SIZE( pxTypeCouples ); x++ ) - { - if( strcasecmp( dot, pxTypeCouples[ x ].pcExtension ) == 0 ) - { - pcResult = pxTypeCouples[ x ].pcType; - break; - } - } - } - return pcResult; -} - -#endif /* ipconfigUSE_HTTP */ - diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/NTP/NTPDemo.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/NTP/NTPDemo.c deleted file mode 100644 index 7795c41da..000000000 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/NTP/NTPDemo.c +++ /dev/null @@ -1,440 +0,0 @@ -/* - * FreeRTOS+TCP V2.0.3 - * 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 - */ - -/* - * NTPDemo.c - * - * An example of how to lookup a domain using DNS - * And also how to send and receive UDP messages to get the NTP time - * - */ - -/* Standard includes. */ -#include -#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" -#include "FreeRTOS_DNS.h" -#include "FreeRTOS_Stream_Buffer.h" - -/* Use the date & time functions from +FAT. */ -#include "ff_time.h" - -#include "NTPDemo.h" -#include "ntpClient.h" - -#include "date_and_time.h" - -enum EStatus { - EStatusLookup, - EStatusAsking, - EStatusPause, - EStatusFailed, -}; - -static struct SNtpPacket xNTPPacket; - -#if( ipconfigUSE_CALLBACKS == 0 ) - static char cRecvBuffer[ sizeof( struct SNtpPacket ) + 64 ]; -#endif - -static enum EStatus xStatus = EStatusLookup; - -static const char *pcTimeServers[] = { - "0.asia.pool.ntp.org", - "0.europe.pool.ntp.org", - "0.id.pool.ntp.org", - "0.south-america.pool.ntp.org", - "0.oceania.pool.ntp.org", - "0.north-america.pool.ntp.org" -}; - -static SemaphoreHandle_t xNTPWakeupSem = NULL; -static uint32_t ulIPAddressFound; -static Socket_t xUDPSocket = NULL; -static TaskHandle_t xNTPTaskhandle = NULL; -static TickType_t uxSendTime; - -static void prvNTPTask( void *pvParameters ); - -static void vSignalTask( void ) -{ - #if( ipconfigUSE_CALLBACKS == 0 ) - if( xUDPSocket != NULL ) - { - /* Send a signal to the socket so that the - FreeRTOS_recvfrom will get interrupted. */ - FreeRTOS_SignalSocket( xUDPSocket ); - } - else - #endif - if( xNTPWakeupSem != NULL ) - { - xSemaphoreGive( xNTPWakeupSem ); - } -} - -void vStartNTPTask( uint16_t usTaskStackSize, UBaseType_t uxTaskPriority ) -{ - /* The only public function in this module: start a task to contact - some NTP server. */ - - if( xNTPTaskhandle != NULL ) - { - switch( xStatus ) - { - case EStatusPause: - xStatus = EStatusAsking; - vSignalTask(); - break; - case EStatusLookup: - FreeRTOS_printf( ( "NTP looking up server\n" ) ); - break; - case EStatusAsking: - FreeRTOS_printf( ( "NTP still asking\n" ) ); - break; - case EStatusFailed: - FreeRTOS_printf( ( "NTP failed somehow\n" ) ); - ulIPAddressFound = 0ul; - xStatus = EStatusLookup; - vSignalTask(); - break; - } - } - else - { - xUDPSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP ); - if( xUDPSocket != NULL ) - { - struct freertos_sockaddr xAddress; - #if( ipconfigUSE_CALLBACKS != 0 ) - BaseType_t xReceiveTimeOut = pdMS_TO_TICKS( 0 ); - #else - BaseType_t xReceiveTimeOut = pdMS_TO_TICKS( 5000 ); - #endif - - xAddress.sin_addr = 0ul; - xAddress.sin_port = FreeRTOS_htons( NTP_PORT ); - - FreeRTOS_bind( xUDPSocket, &xAddress, sizeof( xAddress ) ); - FreeRTOS_setsockopt( xUDPSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) ); - xTaskCreate( prvNTPTask, /* The function that implements the task. */ - ( const char * ) "NTP client", /* Just a text name for the task to aid debugging. */ - usTaskStackSize, /* The stack size is defined in FreeRTOSIPConfig.h. */ - NULL, /* The task parameter, not used in this case. */ - uxTaskPriority, /* The priority assigned to the task is defined in FreeRTOSConfig.h. */ - &xNTPTaskhandle ); /* The task handle. */ - } - else - { - FreeRTOS_printf( ( "Creating socket failed\n" ) ); - } - } -} -/*-----------------------------------------------------------*/ - -static void vDNS_callback( const char *pcName, void *pvSearchID, uint32_t ulIPAddress ) -{ -char pcBuf[16]; - - /* The DNS lookup has a result, or it has reached the time-out. */ - FreeRTOS_inet_ntoa( ulIPAddress, pcBuf ); - FreeRTOS_printf( ( "IP address of %s found: %s\n", pcName, pcBuf ) ); - if( ulIPAddressFound == 0ul ) - { - ulIPAddressFound = ulIPAddress; - } - /* For testing: in case DNS doen't respond, still try some NTP server - with a known IP-address. */ - if( ulIPAddressFound == 0ul ) - { - ulIPAddressFound = FreeRTOS_inet_addr_quick( 184, 105, 182, 7 ); -/* ulIPAddressFound = FreeRTOS_inet_addr_quick( 103, 242, 70, 4 ); */ - } - xStatus = EStatusAsking; - - vSignalTask(); -} -/*-----------------------------------------------------------*/ - -static void prvSwapFields( struct SNtpPacket *pxPacket) -{ - /* NTP messages are big-endian */ - pxPacket->rootDelay = FreeRTOS_htonl( pxPacket->rootDelay ); - pxPacket->rootDispersion = FreeRTOS_htonl( pxPacket->rootDispersion ); - - pxPacket->referenceTimestamp.seconds = FreeRTOS_htonl( pxPacket->referenceTimestamp.seconds ); - pxPacket->referenceTimestamp.fraction = FreeRTOS_htonl( pxPacket->referenceTimestamp.fraction ); - - pxPacket->originateTimestamp.seconds = FreeRTOS_htonl( pxPacket->originateTimestamp.seconds ); - pxPacket->originateTimestamp.fraction = FreeRTOS_htonl( pxPacket->originateTimestamp.fraction ); - - pxPacket->receiveTimestamp.seconds = FreeRTOS_htonl( pxPacket->receiveTimestamp.seconds ); - pxPacket->receiveTimestamp.fraction = FreeRTOS_htonl( pxPacket->receiveTimestamp.fraction ); - - pxPacket->transmitTimestamp.seconds = FreeRTOS_htonl( pxPacket->transmitTimestamp.seconds ); - pxPacket->transmitTimestamp.fraction = FreeRTOS_htonl( pxPacket->transmitTimestamp.fraction ); -} -/*-----------------------------------------------------------*/ - -static void prvNTPPacketInit( ) -{ - memset (&xNTPPacket, '\0', sizeof( xNTPPacket ) ); - - xNTPPacket.flags = 0xDB; /* value 0xDB : mode 3 (client), version 3, leap indicator unknown 3 */ - xNTPPacket.poll = 10; /* 10 means 1 << 10 = 1024 seconds */ - xNTPPacket.precision = 0xFA; /* = 250 = 0.015625 seconds */ - xNTPPacket.rootDelay = 0x5D2E; /* 0x5D2E = 23854 or (23854/65535)= 0.3640 sec */ - xNTPPacket.rootDispersion = 0x0008CAC8; /* 0x0008CAC8 = 8.7912 seconds */ - - /* use the recorded NTP time */ - time_t uxSecs = FreeRTOS_time( NULL );/* apTime may be NULL, returns seconds */ - - xNTPPacket.referenceTimestamp.seconds = uxSecs; /* Current time */ - xNTPPacket.transmitTimestamp.seconds = uxSecs + 3; - - /* Transform the contents of the fields from native to big endian. */ - prvSwapFields( &xNTPPacket ); -} -/*-----------------------------------------------------------*/ - -static void prvReadTime( struct SNtpPacket * pxPacket ) -{ - FF_TimeStruct_t xTimeStruct; - time_t uxPreviousSeconds; - time_t uxPreviousMS; - - time_t uxCurrentSeconds; - time_t uxCurrentMS; - - const char *pcTimeUnit; - int32_t ilDiff; - TickType_t uxTravelTime; - - uxTravelTime = xTaskGetTickCount() - uxSendTime; - - /* Transform the contents of the fields from big to native endian. */ - prvSwapFields( pxPacket ); - - uxCurrentSeconds = pxPacket->receiveTimestamp.seconds - TIME1970; - uxCurrentMS = pxPacket->receiveTimestamp.fraction / 4294967; - uxCurrentSeconds += uxCurrentMS / 1000; - uxCurrentMS = uxCurrentMS % 1000; - - // Get the last time recorded - uxPreviousSeconds = FreeRTOS_get_secs_msec( &uxPreviousMS ); - - // Set the new time with precision in msec. */ - FreeRTOS_set_secs_msec( &uxCurrentSeconds, &uxCurrentMS ); - - if( uxCurrentSeconds >= uxPreviousSeconds ) - { - ilDiff = ( int32_t ) ( uxCurrentSeconds - uxPreviousSeconds ); - } - else - { - ilDiff = 0 - ( int32_t ) ( uxPreviousSeconds - uxCurrentSeconds ); - } - - if( ( ilDiff < -5 ) || ( ilDiff > 5 ) ) - { - /* More than 5 seconds difference. */ - pcTimeUnit = "sec"; - } - else - { - /* Less than or equal to 5 second difference. */ - pcTimeUnit = "ms"; - uint32_t ulLowest = ( uxCurrentSeconds <= uxPreviousSeconds ) ? uxCurrentSeconds : uxPreviousSeconds; - int32_t iCurMS = 1000 * ( uxCurrentSeconds - ulLowest ) + uxCurrentMS; - int32_t iPrevMS = 1000 * ( uxPreviousSeconds - ulLowest ) + uxPreviousMS; - ilDiff = iCurMS - iPrevMS; - } - uxCurrentSeconds -= iTimeZone; - - FreeRTOS_gmtime_r( &uxCurrentSeconds, &xTimeStruct ); - - /* - 378.067 [NTP client] NTP time: 9/11/2015 16:11:19.559 Diff -20 ms (289 ms) - 379.441 [NTP client] NTP time: 9/11/2015 16:11:20.933 Diff 0 ms (263 ms) - */ - - FreeRTOS_printf( ("NTP time: %d/%d/%02d %2d:%02d:%02d.%03u Diff %d %s (%lu ms)\n", - xTimeStruct.tm_mday, - xTimeStruct.tm_mon + 1, - xTimeStruct.tm_year + 1900, - xTimeStruct.tm_hour, - xTimeStruct.tm_min, - xTimeStruct.tm_sec, - ( unsigned )uxCurrentMS, - ( unsigned )ilDiff, - pcTimeUnit, - uxTravelTime ) ); - - /* Remove compiler warnings in case FreeRTOS_printf() is not used. */ - ( void ) pcTimeUnit; - ( void ) uxTravelTime; -} -/*-----------------------------------------------------------*/ - -#if( ipconfigUSE_CALLBACKS != 0 ) - - static BaseType_t xOnUDPReceive( Socket_t xSocket, void * pvData, size_t xLength, - const struct freertos_sockaddr *pxFrom, const struct freertos_sockaddr *pxDest ) - { - if( xLength >= sizeof( xNTPPacket ) ) - { - prvReadTime( ( struct SNtpPacket *)pvData ); - if( xStatus != EStatusPause ) - { - xStatus = EStatusPause; - } - } - vSignalTask(); - /* Tell the driver not to store the RX data */ - return 1; - } - /*-----------------------------------------------------------*/ - -#endif /* ipconfigUSE_CALLBACKS != 0 */ - -static void prvNTPTask( void *pvParameters ) -{ -BaseType_t xServerIndex = 3; -struct freertos_sockaddr xAddress; -#if( ipconfigUSE_CALLBACKS != 0 ) - F_TCP_UDP_Handler_t xHandler; -#endif /* ipconfigUSE_CALLBACKS != 0 */ - - xStatus = EStatusLookup; - #if( ipconfigSOCKET_HAS_USER_SEMAPHORE != 0 ) || ( ipconfigUSE_CALLBACKS != 0 ) - { - xNTPWakeupSem = xSemaphoreCreateBinary(); - } - #endif - - #if( ipconfigUSE_CALLBACKS != 0 ) - { - memset( &xHandler, '\0', sizeof( xHandler ) ); - xHandler.pxOnUDPReceive = xOnUDPReceive; - FreeRTOS_setsockopt( xUDPSocket, 0, FREERTOS_SO_UDP_RECV_HANDLER, ( void * ) &xHandler, sizeof( xHandler ) ); - } - #endif - #if( ipconfigSOCKET_HAS_USER_SEMAPHORE != 0 ) - { - FreeRTOS_setsockopt( xUDPSocket, 0, FREERTOS_SO_SET_SEMAPHORE, ( void * ) &xNTPWakeupSem, sizeof( xNTPWakeupSem ) ); - } - #endif - for( ; ; ) - { - switch( xStatus ) - { - case EStatusLookup: - if( ( ulIPAddressFound == 0ul ) || ( ulIPAddressFound == ~0ul ) ) - { - if( ++xServerIndex == sizeof( pcTimeServers ) / sizeof( pcTimeServers[ 0 ] ) ) - { - xServerIndex = 0; - } - FreeRTOS_printf( ( "Looking up server '%s'\n", pcTimeServers[ xServerIndex ] ) ); - FreeRTOS_gethostbyname_a( pcTimeServers[ xServerIndex ], vDNS_callback, (void *)NULL, 1200 ); - } - else - { - xStatus = EStatusAsking; - } - break; - - case EStatusAsking: - { - char pcBuf[16]; - - prvNTPPacketInit( ); - xAddress.sin_addr = ulIPAddressFound; - xAddress.sin_port = FreeRTOS_htons( NTP_PORT ); - - FreeRTOS_inet_ntoa( xAddress.sin_addr, pcBuf ); - FreeRTOS_printf( ( "Sending UDP message to %s:%u\n", - pcBuf, - FreeRTOS_ntohs( xAddress.sin_port ) ) ); - - uxSendTime = xTaskGetTickCount( ); - FreeRTOS_sendto( xUDPSocket, ( void * )&xNTPPacket, sizeof( xNTPPacket ), 0, &xAddress, sizeof( xAddress ) ); - } - break; - - case EStatusPause: - break; - - case EStatusFailed: - break; - } - - #if( ipconfigUSE_CALLBACKS != 0 ) - { - xSemaphoreTake( xNTPWakeupSem, 5000 ); - } - #else - { - uint32_t xAddressSize; - BaseType_t xReturned; - - xAddressSize = sizeof( xAddress ); - xReturned = FreeRTOS_recvfrom( xUDPSocket, ( void * ) cRecvBuffer, sizeof( cRecvBuffer ), 0, &xAddress, &xAddressSize ); - switch( xReturned ) - { - case 0: - case -pdFREERTOS_ERRNO_EAGAIN: - case -pdFREERTOS_ERRNO_EINTR: - break; - default: - if( xReturned < sizeof( xNTPPacket ) ) - { - FreeRTOS_printf( ( "FreeRTOS_recvfrom: returns %ld\n", xReturned ) ); - } - else - { - prvReadTime( ( struct SNtpPacket *)cRecvBuffer ); - if( xStatus != EStatusPause ) - { - xStatus = EStatusPause; - } - } - break; - } - } - #endif - } -} -/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/FreeRTOS_FTP_commands.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/FreeRTOS_FTP_commands.h deleted file mode 100644 index 6ae2384d9..000000000 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/FreeRTOS_FTP_commands.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * FreeRTOS+TCP V2.0.1 - * 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 - */ - -#ifndef __FTPCMD_H__ - -#define __FTPCMD_H__ - -#define REPL_110 "110 Restart marker reply.\r\n" -#define REPL_120 "120 Try again in 2 minutes.\r\n" -#define REPL_125 "125 Data connection already open; transfer starting.\r\n" -#define REPL_150 "150 File status okay; about to open data connection.\r\n" -#define REPL_200 "200 NOOP command successful.\r\n" -#define REPL_200_PROGRESS "200 NOOP: data transfer in progress.\r\n" -#define REPL_202 "202 Command not implemented, superfluous at this site.\r\n" -#define REPL_211 "221 System status, or system help reply.\r\n" -#define REPL_211_STATUS "221-status of %s.\r\n" -#define REPL_211_END "221 End of status.\r\n" -#define REPL_212 "212 Directory status.\r\n" -#define REPL_213 "213 File status.\r\n" -#define REPL_214 "214 Help message.\r\n" -#define REPL_214_END "214 End Help message.\r\n" -#define REPL_215 "215 %s system type.\r\n" -#define REPL_220 "220 Service ready for new user.\r\n" -#define REPL_221 "221 Service closing control connection.\r\n" -#define REPL_225 "225 Data connection open; no transfer in progress.\r\n" -#define REPL_226 "226 Closing data connection.\r\n" -#define REPL_227 "227 Entering Passive Mode (%s,%s,%s,%s,%s,%s).\r\n" -#define REPL_227_D "227 Entering Passive Mode (%u,%u,%u,%u,%u,%u).\r\n" -#define REPL_230 "230 User logged in, proceed.\r\n" -#define REPL_250 "250 Requested file action okay, completed.\r\n" -#define REPL_257 "257 %s created.\r\n" -// #define REPL_257_PWD "257 \"%s\" is current working dir.\r\n" -#define REPL_257_PWD "257 \"%s\"\r\n" -#define REPL_331 "331 Only anonymous user is accepted.\r\n" -#define REPL_331_ANON "331 Anonymous login okay\r\n" -#define REPL_332 "332 Need account for login.\r\n" -#define REPL_350 "350 Requested file action pending further information.\r\n" -#define REPL_421 "421 Service not available, closing control connection.\r\n" -#define REPL_425 "425 Can't open data connection.\r\n" -#define REPL_426 "426 Connection closed; transfer aborted.\r\n" -#define REPL_450 "450 Requested file action not taken.\r\n" -#define REPL_451 "451 Requested action aborted. Local error in processing.\r\n" -#define REPL_452 "452 Requested action not taken.\r\n" -#define REPL_500 "500 Syntax error, command unrecognized.\r\n" -#define REPL_501 "501 Syntax error in parameters or arguments.\r\n" -#define REPL_502 "502 Command not implemented.\r\n" -#define REPL_503 "503 Bad sequence of commands.\r\n" -#define REPL_504 "504 Command not implemented for that parameter.\r\n" -#define REPL_530 "530 Not logged in.\r\n" -#define REPL_532 "532 Need account for storing files.\r\n" -#define REPL_550 "550 Requested action not taken.\r\n" -#define REPL_551 "551 Requested action aborted. Page type unknown.\r\n" -#define REPL_552 "552 Requested file action aborted.\r\n" -#define REPL_553 "553 Requested action not taken.\r\n" -#define REPL_553_READ_ONLY "553 Read-only file-system.\r\n" - -enum EFTPCommand { - ECMD_USER, - ECMD_PASS, - ECMD_ACCT, - ECMD_CWD, - ECMD_CDUP, - ECMD_SMNT, - ECMD_QUIT, - ECMD_REIN, - ECMD_PORT, - ECMD_PASV, - ECMD_TYPE, - ECMD_STRU, - ECMD_MODE, - ECMD_RETR, - ECMD_STOR, - ECMD_STOU, - ECMD_APPE, - ECMD_ALLO, - ECMD_REST, - ECMD_RNFR, - ECMD_RNTO, - ECMD_ABOR, - ECMD_SIZE, - ECMD_MDTM, - ECMD_DELE, - ECMD_RMD, - ECMD_MKD, - ECMD_PWD, - ECMD_LIST, - ECMD_NLST, - ECMD_SITE, - ECMD_SYST, - ECMD_FEAT, - ECMD_STAT, - ECMD_HELP, - ECMD_NOOP, - ECMD_EMPTY, - ECMD_CLOSE, - ECMD_UNKNOWN, -}; - -typedef struct xFTP_COMMAND { - BaseType_t xCommandLength; - const char pcCommandName[7]; - const unsigned char ucCommandType; - const unsigned char checkLogin; - const unsigned char checkNullArg; -} FTPCommand_t; - -#define FTP_CMD_COUNT (ECMD_UNKNOWN+1) - -extern const FTPCommand_t xFTPCommands[ FTP_CMD_COUNT ]; - -#endif // __FTPCMD_H__ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/FreeRTOS_HTTP_commands.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/FreeRTOS_HTTP_commands.h deleted file mode 100644 index 75eaf5d9f..000000000 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/FreeRTOS_HTTP_commands.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * FreeRTOS+TCP V2.0.3 - * 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 - */ -#ifndef FREERTOS_HTTP_COMMANDS_H -#define FREERTOS_HTTP_COMMANDS_H - -enum { - WEB_REPLY_OK = 200, - WEB_NO_CONTENT = 204, - WEB_BAD_REQUEST = 400, - WEB_UNAUTHORIZED = 401, - WEB_NOT_FOUND = 404, - WEB_GONE = 410, - WEB_PRECONDITION_FAILED = 412, - WEB_INTERNAL_SERVER_ERROR = 500, -}; - -enum EWebCommand { - ECMD_GET, - ECMD_HEAD, - ECMD_POST, - ECMD_PUT, - ECMD_DELETE, - ECMD_TRACE, - ECMD_OPTIONS, - ECMD_CONNECT, - ECMD_PATCH, - ECMD_UNK, -}; - -struct xWEB_COMMAND -{ - BaseType_t xCommandLength; - const char *pcCommandName; - const unsigned char ucCommandType; -}; - -#define WEB_CMD_COUNT (ECMD_UNK+1) - -extern const struct xWEB_COMMAND xWebCommands[WEB_CMD_COUNT]; - -extern const char *webCodename (int aCode); - -#endif /* FREERTOS_HTTP_COMMANDS_H */ - - diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/FreeRTOS_TCP_server.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/FreeRTOS_TCP_server.h deleted file mode 100644 index d8140ce82..000000000 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/FreeRTOS_TCP_server.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * FreeRTOS+TCP V2.0.3 - * 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 - */ - -/* - Some code which is common to TCP servers like HTTP en FTP -*/ - -#ifndef FREERTOS_TCP_SERVER_H -#define FREERTOS_TCP_SERVER_H - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef FTP_SERVER_USES_RELATIVE_DIRECTORY - #define FTP_SERVER_USES_RELATIVE_DIRECTORY 0 -#endif - -enum eSERVER_TYPE -{ - eSERVER_NONE, - eSERVER_HTTP, - eSERVER_FTP, -}; - -struct xFTP_CLIENT; - -#if( ipconfigFTP_HAS_RECEIVED_HOOK != 0 ) - extern void vApplicationFTPReceivedHook( const char *pcFileName, uint32_t ulSize, struct xFTP_CLIENT *pxFTPClient ); - extern void vFTPReplyMessage( struct xFTP_CLIENT *pxFTPClient, const char *pcMessage ); -#endif /* ipconfigFTP_HAS_RECEIVED_HOOK != 0 */ - -#if( ipconfigFTP_HAS_USER_PASSWORD_HOOK != 0 ) - /* - * Function is called when a user name has been submitted. - * The function may return a string such as: "331 Please enter your password" - * or return NULL to use the default reply. - */ - extern const char *pcApplicationFTPUserHook( const char *pcUserName ); -#endif /* ipconfigFTP_HAS_USER_PASSWORD_HOOK */ - -#if( ipconfigFTP_HAS_USER_PASSWORD_HOOK != 0 ) - /* - * Function is called when a password was received. - * Return positive value to allow the user - */ - extern BaseType_t xApplicationFTPPasswordHook( const char *pcUserName, const char *pcPassword ); -#endif /* ipconfigFTP_HAS_USER_PASSWORD_HOOK */ - -#if( ipconfigFTP_HAS_USER_PROPERTIES_HOOK != 0 ) - /* - * The FTP server is asking for user-specific properties - */ - typedef struct - { - uint16_t usPortNumber; /* For reference only. Host-endian. */ - const char *pcRootDir; - BaseType_t xReadOnly; - } - FTPUserProperties_t; - extern void vApplicationFTPUserPropertiesHook( const char *pcUserName, FTPUserProperties_t *pxProperties ); -#endif /* ipconfigFTP_HAS_USER_PASSWORD_HOOK */ - -#if( ipconfigHTTP_HAS_HANDLE_REQUEST_HOOK != 0 ) - /* - * A GET request is received containing a special character, - * usually a question mark. - * const char *pcURLData; // A request, e.g. "/request?limit=75" - * char *pcBuffer; // Here the answer can be written - * size_t uxBufferLength; // Size of the buffer - * - */ - extern size_t uxApplicationHTTPHandleRequestHook( const char *pcURLData, char *pcBuffer, size_t uxBufferLength ); -#endif /* ipconfigHTTP_HAS_HANDLE_REQUEST_HOOK */ - -struct xSERVER_CONFIG -{ - enum eSERVER_TYPE eType; /* eSERVER_HTTP | eSERVER_FTP */ - BaseType_t xPortNumber; /* e.g. 80, 8080, 21 */ - BaseType_t xBackLog; /* e.g. 10, maximum number of connected TCP clients */ - const char * const pcRootDir; /* Treat this directory as the root directory */ -}; - -struct xTCP_SERVER; -typedef struct xTCP_SERVER TCPServer_t; - -TCPServer_t *FreeRTOS_CreateTCPServer( const struct xSERVER_CONFIG *pxConfigs, BaseType_t xCount ); -void FreeRTOS_TCPServerWork( TCPServer_t *pxServer, TickType_t xBlockingTime ); - -#if( ipconfigSUPPORT_SIGNALS != 0 ) - /* FreeRTOS_TCPServerWork() calls select(). - The two functions below provide a possibility to interrupt - the call to select(). After the interruption, resume - by calling FreeRTOS_TCPServerWork() again. */ - BaseType_t FreeRTOS_TCPServerSignal( TCPServer_t *pxServer ); - BaseType_t FreeRTOS_TCPServerSignalFromISR( TCPServer_t *pxServer, BaseType_t *pxHigherPriorityTaskWoken ); -#endif - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* FREERTOS_TCP_SERVER_H */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/FreeRTOS_server_private.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/FreeRTOS_server_private.h deleted file mode 100644 index 73768040e..000000000 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/FreeRTOS_server_private.h +++ /dev/null @@ -1,185 +0,0 @@ -/* - * FreeRTOS+TCP V2.0.3 - * 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 - */ - - /* - Some code which is common to TCP servers like HTTP and FTP -*/ - -#ifndef FREERTOS_SERVER_PRIVATE_H -#define FREERTOS_SERVER_PRIVATE_H - -#define FREERTOS_NO_SOCKET NULL - -/* FreeRTOS+FAT */ -#include "ff_stdio.h" - -/* Each HTTP server has 1, at most 2 sockets */ -#define HTTP_SOCKET_COUNT 2 - -/* - * ipconfigTCP_COMMAND_BUFFER_SIZE sets the size of: - * pcCommandBuffer': a buffer to receive and send TCP commands - * - * ipconfigTCP_FILE_BUFFER_SIZE sets the size of: - * pcFileBuffer' : a buffer to access the file system: read or write data. - * - * The buffers are both used for FTP as well as HTTP. - */ - -#ifndef ipconfigTCP_COMMAND_BUFFER_SIZE - #define ipconfigTCP_COMMAND_BUFFER_SIZE ( 2048 ) -#endif - -#ifndef ipconfigTCP_FILE_BUFFER_SIZE - #define ipconfigTCP_FILE_BUFFER_SIZE ( 2048 ) -#endif - -struct xTCP_CLIENT; - -typedef BaseType_t ( * FTCPWorkFunction ) ( struct xTCP_CLIENT * /* pxClient */ ); -typedef void ( * FTCPDeleteFunction ) ( struct xTCP_CLIENT * /* pxClient */ ); - -#define TCP_CLIENT_FIELDS \ - enum eSERVER_TYPE eType; \ - struct xTCP_SERVER *pxParent; \ - Socket_t xSocket; \ - const char *pcRootDir; \ - FTCPWorkFunction fWorkFunction; \ - FTCPDeleteFunction fDeleteFunction; \ - struct xTCP_CLIENT *pxNextClient - -typedef struct xTCP_CLIENT -{ - /* This define contains fields which must come first within each of the client structs */ - TCP_CLIENT_FIELDS; - /* --- Keep at the top --- */ - -} TCPClient_t; - -struct xHTTP_CLIENT -{ - /* This define contains fields which must come first within each of the client structs */ - TCP_CLIENT_FIELDS; - /* --- Keep at the top --- */ - - const char *pcUrlData; - const char *pcRestData; - char pcCurrentFilename[ ffconfigMAX_FILENAME ]; - size_t uxBytesLeft; - FF_FILE *pxFileHandle; - union { - struct { - uint32_t - bReplySent : 1; - }; - uint32_t ulFlags; - } bits; -}; - -typedef struct xHTTP_CLIENT HTTPClient_t; - -struct xFTP_CLIENT -{ - /* This define contains fields which must come first within each of the client structs */ - TCP_CLIENT_FIELDS; - /* --- Keep at the top --- */ - - uint32_t ulRestartOffset; - uint32_t ulRecvBytes; - size_t uxBytesLeft; /* Bytes left to send */ - uint32_t ulClientIP; - TickType_t xStartTime; - uint16_t usClientPort; - Socket_t xTransferSocket; - BaseType_t xTransType; - BaseType_t xDirCount; - FF_FindData_t xFindData; - FF_FILE *pxReadHandle; - FF_FILE *pxWriteHandle; - char pcCurrentDir[ ffconfigMAX_FILENAME ]; - char pcFileName[ ffconfigMAX_FILENAME ]; - char pcConnectionAck[ 128 ]; - char pcClientAck[ 128 ]; - union { - struct { - uint32_t - bHelloSent : 1, - bLoggedIn : 1, - bStatusUser : 1, - bInRename : 1, - bReadOnly : 1; - }; - uint32_t ulFTPFlags; - } bits; - union { - struct { - uint32_t - bIsListen : 1, /* pdTRUE for passive data connections (using list()). */ - bDirHasEntry : 1, /* pdTRUE if ff_findfirst() was successful. */ - bClientConnected : 1, /* pdTRUE after connect() or accept() has succeeded. */ - bEmptyFile : 1, /* pdTRUE if a connection-without-data was received. */ - bHadError : 1; /* pdTRUE if a transfer got aborted because of an error. */ - }; - uint32_t ulConnFlags; - } bits1; -}; - -typedef struct xFTP_CLIENT FTPClient_t; - -BaseType_t xHTTPClientWork( TCPClient_t *pxClient ); -BaseType_t xFTPClientWork( TCPClient_t *pxClient ); - -void vHTTPClientDelete( TCPClient_t *pxClient ); -void vFTPClientDelete( TCPClient_t *pxClient ); - -BaseType_t xMakeAbsolute( struct xFTP_CLIENT *pxClient, char *pcBuffer, BaseType_t xBufferLength, const char *pcFileName ); -BaseType_t xMakeRelative( FTPClient_t *pxClient, char *pcBuffer, BaseType_t xBufferLength, const char *pcFileName ); - -struct xTCP_SERVER -{ - SocketSet_t xSocketSet; - /* A buffer to receive and send TCP commands, either HTTP of FTP. */ - char pcCommandBuffer[ ipconfigTCP_COMMAND_BUFFER_SIZE ]; - /* A buffer to access the file system: read or write data. */ - char pcFileBuffer[ ipconfigTCP_FILE_BUFFER_SIZE ]; - - #if( ipconfigUSE_FTP != 0 ) - char pcNewDir[ ffconfigMAX_FILENAME ]; - #endif - #if( ipconfigUSE_HTTP != 0 ) - char pcContentsType[40]; /* Space for the msg: "text/javascript" */ - char pcExtraContents[40]; /* Space for the msg: "Content-Length: 346500" */ - #endif - BaseType_t xServerCount; - TCPClient_t *pxClients; - struct xSERVER - { - enum eSERVER_TYPE eType; /* eSERVER_HTTP | eSERVER_FTP */ - const char *pcRootDir; - Socket_t xSocket; - } xServers[ 1 ]; -}; - -#endif /* FREERTOS_SERVER_PRIVATE_H */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/NTPClient.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/NTPClient.h deleted file mode 100644 index 813539e6e..000000000 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/NTPClient.h +++ /dev/null @@ -1,71 +0,0 @@ -// -// ntpClient.h -// - -#ifndef __NTPCLIENT_H__ - -#define __NTPCLIENT_H__ - -#define NTP_PORT 123 - -typedef uint32_t quint32; -typedef int32_t qint32; -typedef uint8_t quint8; -typedef int8_t qint8; - -typedef union _SNtpFlags SNtpFlags; - -/** - * 64-bit NTP timestamp. - */ -struct __attribute__ ((__packed__)) _SNtpTimestamp { - /** Number of seconds passed since Jan 1 1900, in big-endian format. */ - quint32 seconds; - - /** Fractional time part, in 1/0xFFFFFFFFs of a second. */ - quint32 fraction; -}; - -typedef struct _SNtpTimestamp SNtpTimestamp; -/** - * Mandatory part of an NTP packet - */ -struct SNtpPacket { - /** Flags. */ - unsigned char flags; // value 0xDB : mode 3 (client), version 3, leap indicator unknown 3 - - /** Stratum of the clock. */ - quint8 stratum; // value 0 : unspecified - - /** Maximum interval between successive messages, in log2 seconds. Note that the value is signed. */ - qint8 poll; // 10 means 1 << 10 = 1024 seconds - - /** Precision of the clock, in log2 seconds. Note that the value is signed. */ - qint8 precision; // 0xFA = 250 = 0.015625 seconds - - /** Round trip time to the primary reference source, in NTP short format. */ - qint32 rootDelay; // 0x5D2E = 23854 or (23854/65535)= 0.3640 sec - - /** Nominal error relative to the primary reference source. */ - qint32 rootDispersion; // 0x0008 CAC8 = 8.7912 seconds - - /** Reference identifier (either a 4 character string or an IP address). */ - qint8 referenceID[4]; // or just 0000 - - /** The time at which the clock was last set or corrected. */ - SNtpTimestamp referenceTimestamp; // Current time - - /** The time at which the request departed the client for the server. */ - SNtpTimestamp originateTimestamp; // Keep 0 - - /** The time at which the request arrived at the server. */ - SNtpTimestamp receiveTimestamp; // Keep 0 - - /** The time at which the reply departed the server for client. */ - SNtpTimestamp transmitTimestamp; -}; - -/* Add this number to get secs since 1-1-1900 */ -#define TIME1970 2208988800UL - -#endif // __NTPCLIENT_H__ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/NTPDemo.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/NTPDemo.h deleted file mode 100644 index e75fb76aa..000000000 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/include/NTPDemo.h +++ /dev/null @@ -1,11 +0,0 @@ -/* - * A simple demo for NTP using FreeRTOS+TCP - */ - -#ifndef NTPDEMO_H - -#define NTPDEMO_H - -void vStartNTPTask( uint16_t usTaskStackSize, UBaseType_t uxTaskPriority ); - -#endif \ No newline at end of file diff --git a/FreeRTOS/Demo/CORTEX_A5_SAMA5D2x_Xplained_IAR/RTOSDemo.ewp b/FreeRTOS/Demo/CORTEX_A5_SAMA5D2x_Xplained_IAR/RTOSDemo.ewp index 6860b54ed..654b3b930 100644 --- a/FreeRTOS/Demo/CORTEX_A5_SAMA5D2x_Xplained_IAR/RTOSDemo.ewp +++ b/FreeRTOS/Demo/CORTEX_A5_SAMA5D2x_Xplained_IAR/RTOSDemo.ewp @@ -11,7 +11,7 @@ General 3 - 29 + 30 1 1 + @@ -620,6 +624,7 @@ @@ -1038,7 +1042,7 @@ General 3 - 29 + 30 1 1 + @@ -1644,6 +1652,7 @@ AUserIncludes $PROJ_DIR$\..\..\..\libraries $PROJ_DIR$/. + $PROJ_DIR$\..\..\Source\portable\IAR\ARM_CA5_No_GIC