You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
583 lines
22 KiB
C
583 lines
22 KiB
C
/*
|
|
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
|
All rights reserved
|
|
|
|
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
|
|
|
This file is part of the FreeRTOS distribution.
|
|
|
|
FreeRTOS is free software; you can redistribute it and/or modify it under
|
|
the terms of the GNU General Public License (version 2) as published by the
|
|
Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
|
|
|
|
***************************************************************************
|
|
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
|
>>! distribute a combined work that includes FreeRTOS without being !<<
|
|
>>! obliged to provide the source code for proprietary components !<<
|
|
>>! outside of the FreeRTOS kernel. !<<
|
|
***************************************************************************
|
|
|
|
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
|
link: http://www.freertos.org/a00114.html
|
|
|
|
***************************************************************************
|
|
* *
|
|
* FreeRTOS provides completely free yet professionally developed, *
|
|
* robust, strictly quality controlled, supported, and cross *
|
|
* platform software that is more than just the market leader, it *
|
|
* is the industry's de facto standard. *
|
|
* *
|
|
* Help yourself get started quickly while simultaneously helping *
|
|
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
|
* tutorial book, reference manual, or both: *
|
|
* http://www.FreeRTOS.org/Documentation *
|
|
* *
|
|
***************************************************************************
|
|
|
|
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
|
the FAQ page "My application does not run, what could be wrong?". Have you
|
|
defined configASSERT()?
|
|
|
|
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
|
embedded software for free we request you assist our global community by
|
|
participating in the support forum.
|
|
|
|
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
|
be as productive as possible as early as possible. Now you can receive
|
|
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
|
Ltd, and the world's leading authority on the world's leading RTOS.
|
|
|
|
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
|
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
|
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
|
|
|
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
|
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
|
|
|
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
|
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
|
licenses offer ticketed support, indemnification and commercial middleware.
|
|
|
|
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
|
engineered and independently SIL3 certified version for use in safety and
|
|
mission critical applications that require provable dependability.
|
|
|
|
1 tab == 4 spaces!
|
|
*/
|
|
|
|
/*
|
|
* A basic TFTP server that can currently only be used to receive files, and not
|
|
* send files. This is a slim implementation intended for use in boot loaders
|
|
* and other applications that require over the air reception of files.
|
|
*/
|
|
|
|
/* Standard includes. */
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
/* FreeRTOS includes. */
|
|
#include "FreeRTOS.h"
|
|
#include "task.h"
|
|
|
|
/* FreeRTOS+TCP includes. */
|
|
#include "FreeRTOS_IP.h"
|
|
#include "FreeRTOS_Sockets.h"
|
|
|
|
/* FreeRTOS+FAT includes. */
|
|
#include "ff_stdio.h"
|
|
|
|
#if( ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND != 1 )
|
|
#error ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND must be set to one to use this TFTP server.
|
|
#endif
|
|
|
|
#if( configTICK_RATE_HZ > 1000 )
|
|
#error The TFTP server uses the pdMS_TO_TICKS() macro, so configTICK_RATE_HZ must be less than or equal to 1000
|
|
#endif
|
|
|
|
#ifndef ipconfigTFTP_TIME_OUT_MS
|
|
#define ipconfigTFTP_TIME_OUT_MS ( 10000 )
|
|
#endif
|
|
|
|
#ifndef ipconfigTFTP_MAX_RETRIES
|
|
#define ipconfigTFTP_MAX_RETRIES ( 6 )
|
|
#endif
|
|
|
|
/* Standard/expected TFTP port number. */
|
|
#define tftpPORT_NUMBER ( ( uint16_t ) 69 )
|
|
|
|
/* Offset to the file name within the frame. */
|
|
#define tftpFILE_NAME_OFFSET ( 2 )
|
|
|
|
/* Number of bytes in the Ack message. */
|
|
#define tftpACK_MESSAGE_LENGTH 4
|
|
|
|
/* Files are sent in fixed length blocks of 512 (the original maximum). */
|
|
#define tftpMAX_DATA_LENGTH ( ( size_t ) 512 )
|
|
|
|
/* Standard TFTP opcodes. */
|
|
typedef enum
|
|
{
|
|
eReadRequest = 1,
|
|
eWriteRequest,
|
|
eData,
|
|
eAck,
|
|
eError
|
|
} eTFTPOpcode_t;
|
|
|
|
/* Error codes from the RFC. */
|
|
typedef enum
|
|
{
|
|
eFileNotFound = 1,
|
|
eAccessViolation,
|
|
eDiskFull,
|
|
eIllegalTFTPOperation,
|
|
eUnknownTransferID,
|
|
eFileAlreadyExists
|
|
} eTFTPErrorCode_t;
|
|
|
|
/* Header used in data transfer packets. */
|
|
#include "pack_struct_start.h"
|
|
struct DataPacketHeader
|
|
{
|
|
uint16_t usOpcode;
|
|
uint16_t usBlockNumber;
|
|
}
|
|
#include "pack_struct_end.h"
|
|
typedef struct DataPacketHeader TFTPBlockNumberHeader_t;
|
|
|
|
/*
|
|
* Manages a single TFTP connection at a time.
|
|
*/
|
|
static void prvSimpleTFTPServerTask( void *pvParameters );
|
|
|
|
/*
|
|
* Manage the reception of a file. If the file is received correctly then
|
|
* return pdPASS, otherwise return pdFAIL.
|
|
*/
|
|
static BaseType_t prvReceiveFile( FF_FILE *pxFile, struct freertos_sockaddr *pxClient );
|
|
|
|
/*
|
|
* Send an error frame to the client.
|
|
*/
|
|
static void prvSendTFTPError( Socket_t xSocket, struct freertos_sockaddr *pxClient, eTFTPErrorCode_t eErrorCode );
|
|
|
|
/*
|
|
* Check a received write request contains a potentially valid file name string,
|
|
* and is a binary mode transfer. If so return a pointer to the file name with
|
|
* the write request packet received from the network, otherwise return NULL.
|
|
*/
|
|
static const char* prvValidateWriteRequest( Socket_t xSocket, struct freertos_sockaddr *pxClient, uint8_t *pucUDPPayloadBuffer );
|
|
|
|
/*
|
|
* Called after a valid write request has been received to first check the file
|
|
* does not already exist, and if the file does not exist, create the file ready
|
|
* to be written. If the file did already exist, or if the file could not be
|
|
* created, then NULL is returned - otherwise a handle to the created file is
|
|
* returned.
|
|
*/
|
|
static FF_FILE* prvValidateFileToWrite( Socket_t xSocket, struct freertos_sockaddr *pxClient, const char *pcFileName );
|
|
|
|
/*
|
|
* Send an acknowledgement packet to pxClient with block number usBlockNumber.
|
|
*/
|
|
static void prvSendAcknowledgement( Socket_t xSocket, struct freertos_sockaddr *pxClient, uint16_t usBlockNumber );
|
|
|
|
/* The index for the error string below MUST match the value of the applicable
|
|
eTFTPErrorCode_t error code value. */
|
|
static const char *cErrorStrings[] =
|
|
{
|
|
NULL, /* Not valid. */
|
|
"File not found.",
|
|
"Access violation.",
|
|
"Disk full or allocation exceeded.",
|
|
"Illegal TFTP operation.",
|
|
"Unknown transfer ID.",
|
|
"File already exists.",
|
|
"No such user."
|
|
};
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
void vStartTFTPServerTask( uint16_t usStackSize, UBaseType_t uxPriority )
|
|
{
|
|
/* A single server task is created. Currently this is only capable of
|
|
managing one TFTP transfer at a time. */
|
|
xTaskCreate( prvSimpleTFTPServerTask, "TFTPd", usStackSize, NULL, uxPriority, NULL );
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static void prvSimpleTFTPServerTask( void *pvParameters )
|
|
{
|
|
int32_t lBytes;
|
|
uint8_t *pucUDPPayloadBuffer;
|
|
struct freertos_sockaddr xClient, xBindAddress;
|
|
uint32_t xClientLength = sizeof( xClient ), ulIPAddress;
|
|
Socket_t xTFTPListeningSocket;
|
|
const char *pcFileName;
|
|
FF_FILE *pxFile;
|
|
|
|
/* Just to prevent compiler warnings. */
|
|
( void ) pvParameters;
|
|
|
|
/* Attempt to open the socket. The receive block time defaults to the max
|
|
delay, so there is no need to set that separately. */
|
|
xTFTPListeningSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP );
|
|
configASSERT( xTFTPListeningSocket != FREERTOS_INVALID_SOCKET );
|
|
|
|
/* Bind to the standard TFTP port. */
|
|
FreeRTOS_GetAddressConfiguration( &ulIPAddress, NULL, NULL, NULL );
|
|
xBindAddress.sin_addr = ulIPAddress;
|
|
xBindAddress.sin_port = FreeRTOS_htons( tftpPORT_NUMBER );
|
|
FreeRTOS_bind( xTFTPListeningSocket, &xBindAddress, sizeof( xBindAddress ) );
|
|
|
|
for( ;; )
|
|
{
|
|
/* Look for the start of a new transfer on the TFTP port. ulFlags has
|
|
the zero copy bit set (FREERTOS_ZERO_COPY) indicating to the stack that
|
|
a reference to the received data should be passed out to this task using
|
|
the second parameter to the FreeRTOS_recvfrom() call. When this is done
|
|
the IP stack is no longer responsible for releasing the buffer, and the
|
|
task *must* return the buffer to the stack when it is no longer
|
|
needed. */
|
|
lBytes = FreeRTOS_recvfrom( xTFTPListeningSocket, ( void * ) &pucUDPPayloadBuffer, 0, FREERTOS_ZERO_COPY, &xClient, &xClientLength );
|
|
|
|
if( lBytes >= 0 )
|
|
{
|
|
/* Could this be a new write request? The opcode is contained in
|
|
the first two bytes of the received data. */
|
|
if( ( pucUDPPayloadBuffer[ 0 ] == ( uint8_t ) 0 ) && ( pucUDPPayloadBuffer[ 1 ] == ( uint8_t ) eWriteRequest ) )
|
|
{
|
|
/* If the write request is valid pcFileName will get set to
|
|
point to the file name within pucWriteRequestBuffer - otherwise
|
|
an appropriate error will be sent on xTFTPListeningSocket. */
|
|
pcFileName = prvValidateWriteRequest( xTFTPListeningSocket, &xClient, pucUDPPayloadBuffer );
|
|
|
|
if( pcFileName != NULL )
|
|
{
|
|
/* If the file does not already exist, and can be created,
|
|
then xFile will get set to the file's open handle.
|
|
Otherwise an appropriate error will be sent on
|
|
xTFTPListeningSocket. */
|
|
pxFile = prvValidateFileToWrite( xTFTPListeningSocket, &xClient, pcFileName );
|
|
|
|
if( pxFile != NULL )
|
|
{
|
|
/* Manage reception of the file. */
|
|
prvReceiveFile( pxFile, &xClient );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Not a transfer ID handled by this server. */
|
|
prvSendTFTPError( xTFTPListeningSocket, &xClient, eUnknownTransferID );
|
|
}
|
|
|
|
/* The buffer was received using zero copy, so *must* be freed. */
|
|
FreeRTOS_ReleaseUDPPayloadBuffer( pucUDPPayloadBuffer );
|
|
}
|
|
}
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static BaseType_t prvReceiveFile( FF_FILE *pxFile, struct freertos_sockaddr *pxClient )
|
|
{
|
|
BaseType_t xReturn = pdPASS, xRetries = 0;
|
|
uint16_t usExpectedBlockNumber;
|
|
Socket_t xTFTPRxSocket = FREERTOS_INVALID_SOCKET;
|
|
TickType_t xRxTimeout = pdMS_TO_TICKS( ipconfigTFTP_TIME_OUT_MS );
|
|
int32_t lBytes;
|
|
uint8_t *pucFileBuffer;
|
|
struct freertos_sockaddr xClient;
|
|
uint32_t xClientLength = sizeof( xClient );
|
|
TFTPBlockNumberHeader_t *pxHeader;
|
|
size_t xBlocksWritten, xBytesOfFileDataReceived = tftpMAX_DATA_LENGTH;
|
|
const size_t xBlocksToWrite = 1;
|
|
|
|
/* The file is open for writing, now create the socket on which the file
|
|
will be received from the client. Note the socket is not bound here - so
|
|
will be automatically bound to a port number selected by the IP stack when
|
|
it is used for the first time. */
|
|
xTFTPRxSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP );
|
|
|
|
if( xTFTPRxSocket != FREERTOS_INVALID_SOCKET )
|
|
{
|
|
/* The socket's Rx block time is set to the user configurable timeout
|
|
value. */
|
|
FreeRTOS_setsockopt( xTFTPRxSocket, 0, FREERTOS_SO_RCVTIMEO, &xRxTimeout, sizeof( xRxTimeout ) );
|
|
|
|
/* Acknowledge the write request so the client starts to send the file.
|
|
The first acknowledgment does not have a corresponding block number so
|
|
the special case block number 0 is used. */
|
|
usExpectedBlockNumber = 0;
|
|
|
|
do
|
|
{
|
|
/* The acknowledgment sent here may be a duplicate if the last call
|
|
to FreeRTOS_recvfrom() timee out. */
|
|
prvSendAcknowledgement( xTFTPRxSocket, pxClient, usExpectedBlockNumber );
|
|
|
|
/* Wait for next data packet. Zero copy is used so it is the
|
|
responsibility of this task to free the received data once it is no
|
|
longer required. */
|
|
lBytes = FreeRTOS_recvfrom( xTFTPRxSocket, ( void * ) &pucFileBuffer, 0, FREERTOS_ZERO_COPY, &xClient, &xClientLength );
|
|
|
|
if( lBytes == 0 )
|
|
{
|
|
/* Timed out. */
|
|
FreeRTOS_printf( ( "Error: Timeout.\n" ) );
|
|
xRetries++;
|
|
|
|
if( xRetries > ipconfigTFTP_MAX_RETRIES )
|
|
{
|
|
FreeRTOS_printf( ( "Error: Retry limit exceeded.\n" ) );
|
|
xReturn = pdFAIL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Data received. It is expected to be the next sequential
|
|
block. */
|
|
usExpectedBlockNumber++;
|
|
pxHeader = ( TFTPBlockNumberHeader_t * ) pucFileBuffer;
|
|
pxHeader->usOpcode = FreeRTOS_ntohs( pxHeader->usOpcode );
|
|
pxHeader->usBlockNumber = FreeRTOS_ntohs( pxHeader->usBlockNumber );
|
|
|
|
/* Is the data as expected and from the expected IP address and
|
|
port? */
|
|
if( ( pxHeader->usOpcode == ( uint16_t ) eData ) &&
|
|
( pxHeader->usBlockNumber == usExpectedBlockNumber ) &&
|
|
( pxClient->sin_addr == xClient.sin_addr ) &&
|
|
( pxClient->sin_port == xClient.sin_port ) )
|
|
{
|
|
/* Everything in the packet other than the header is file
|
|
data. */
|
|
xBytesOfFileDataReceived = ( size_t ) lBytes - sizeof( TFTPBlockNumberHeader_t );
|
|
FreeRTOS_printf( ( "Received %d bytes of file data.\n", ( int ) xBytesOfFileDataReceived ) );
|
|
|
|
/* Ack the data then write the data to the file. */
|
|
prvSendAcknowledgement( xTFTPRxSocket, pxClient, usExpectedBlockNumber );
|
|
|
|
/* The data is located by jumping over the header. */
|
|
/*_RB_ Is it ok to write 0 bytes? */
|
|
xBlocksWritten = ff_fwrite( pucFileBuffer + sizeof( TFTPBlockNumberHeader_t ),
|
|
xBytesOfFileDataReceived,
|
|
xBlocksToWrite,
|
|
pxFile );
|
|
|
|
if( xBlocksWritten != xBlocksToWrite )
|
|
{
|
|
/* File could not be written. */
|
|
prvSendTFTPError( xTFTPRxSocket, pxClient, eDiskFull );
|
|
xReturn = pdFAIL;
|
|
}
|
|
|
|
/* Start to receive the next block. */
|
|
xRetries = 0;
|
|
}
|
|
else
|
|
{
|
|
prvSendTFTPError( xTFTPRxSocket, pxClient, eIllegalTFTPOperation );
|
|
xReturn = pdFAIL;
|
|
}
|
|
|
|
/* pucFileBuffer was obtained using zero copy mode, so the
|
|
buffer must be freed now its contents have been written to the
|
|
disk. */
|
|
FreeRTOS_ReleaseUDPPayloadBuffer( pucFileBuffer );
|
|
}
|
|
|
|
/* Until a disk write fails, or the maximum number of retries is
|
|
exceeded, or fewer bytes than tftpMAX_DATA_LENGTH are received (which
|
|
indicates the end of the file). */
|
|
} while( ( xReturn != pdFAIL ) && ( xBytesOfFileDataReceived == tftpMAX_DATA_LENGTH ) );
|
|
|
|
FreeRTOS_printf( ( "Closing connection.\n" ) );
|
|
FreeRTOS_closesocket( xTFTPRxSocket );
|
|
}
|
|
else
|
|
{
|
|
/* An error could be returned here, but it is probably cleaner to just
|
|
time out as the error would have to be sent via the listening socket
|
|
outside of this function. */
|
|
FreeRTOS_printf( ( "Could not create socket to receive file.\n" ) );
|
|
}
|
|
|
|
ff_fclose( pxFile );
|
|
|
|
return xReturn;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
void prvSendAcknowledgement( Socket_t xSocket, struct freertos_sockaddr *pxClient, uint16_t usBlockNumber )
|
|
{
|
|
/* Small fixed size buffer, so not much to be gained by using the zero copy
|
|
interface, just send the buffer directly. */
|
|
TFTPBlockNumberHeader_t xAckMessage;
|
|
|
|
xAckMessage.usOpcode = FreeRTOS_htons( ( ( uint16_t ) eAck ) );
|
|
xAckMessage.usBlockNumber = FreeRTOS_htons( usBlockNumber );
|
|
FreeRTOS_sendto( xSocket, ( void * ) &xAckMessage, tftpACK_MESSAGE_LENGTH, 0, pxClient, sizeof( struct freertos_sockaddr ) );
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static FF_FILE* prvValidateFileToWrite( Socket_t xSocket, struct freertos_sockaddr *pxClient, const char *pcFileName )
|
|
{
|
|
FF_FILE *pxFile;
|
|
|
|
FreeRTOS_printf( ( "Write request for %s received\n", pcFileName ) );
|
|
|
|
/* The file cannot be received if it already exists. Attempt to open the
|
|
file in read mode to see if it exists. */
|
|
pxFile = ff_fopen( pcFileName, "r" );
|
|
|
|
if( pxFile != NULL )
|
|
{
|
|
/* Can't receive a new file without deleting the old one first. */
|
|
ff_fclose( pxFile );
|
|
pxFile = NULL;
|
|
prvSendTFTPError( xSocket, pxClient, eFileAlreadyExists );
|
|
}
|
|
else
|
|
{
|
|
/* The file does not already exist. Attempt to open the file in write
|
|
mode, which will cause it to be created. */
|
|
pxFile = ff_fopen( pcFileName, "w" );
|
|
|
|
if( pxFile == NULL )
|
|
{
|
|
/* The file cannot be created. */
|
|
prvSendTFTPError( xSocket, pxClient, eAccessViolation );
|
|
}
|
|
}
|
|
|
|
return pxFile;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static const char* prvValidateWriteRequest( Socket_t xSocket, struct freertos_sockaddr *pxClient, uint8_t *pucUDPPayloadBuffer )
|
|
{
|
|
char *pcFileName;
|
|
BaseType_t x;
|
|
const char *pcOctedMode = "octet";
|
|
|
|
/* pcFileName is set to point to the file name which is inside the write
|
|
request frame, so its important not to free the frame until the operation is
|
|
over. The start of the file name string is after the opcode, so two bytes
|
|
into the packet. */
|
|
pcFileName = ( char * ) &( pucUDPPayloadBuffer[ tftpFILE_NAME_OFFSET ] );
|
|
|
|
/* Sanity check the file name. */
|
|
for( x = 0; x < ffconfigMAX_FILENAME; x++ )
|
|
{
|
|
if( pcFileName[ x ] == 0x00 )
|
|
{
|
|
/* The end of the string was located. */
|
|
break;
|
|
}
|
|
else if( ( pcFileName[ x ] < ' ' ) || ( pcFileName[ x ] > '~' ) )
|
|
{
|
|
/* Not a valid file name character. */
|
|
pcFileName = NULL;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
/* Just a character in the file name. */
|
|
}
|
|
}
|
|
|
|
if( pcFileName != NULL )
|
|
{
|
|
/* Only binary transfers are supported, indicated by an 'octet' mode
|
|
string following the file name. +1 to move past the null terminator to
|
|
the start of the next string. */
|
|
x++;
|
|
if( strcmpi( pcOctedMode, ( const char * ) &( pucUDPPayloadBuffer[ tftpFILE_NAME_OFFSET + x ] ) ) != 0 )
|
|
{
|
|
/* Not the expected mode. */
|
|
prvSendTFTPError( xSocket, pxClient, eIllegalTFTPOperation );
|
|
pcFileName = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
prvSendTFTPError( xSocket, pxClient, eFileNotFound );
|
|
}
|
|
|
|
return pcFileName;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static void prvSendTFTPError( Socket_t xSocket, struct freertos_sockaddr *pxClient, eTFTPErrorCode_t eErrorCode )
|
|
{
|
|
uint8_t *pucUDPPayloadBuffer = NULL;
|
|
const size_t xFixedSizePart = ( size_t ) 5; /* 2 byte opcode, plus two byte error code, plus string terminating 0. */
|
|
const size_t xNumberOfErrorStrings = sizeof( cErrorStrings ) / sizeof( char * );
|
|
size_t xErrorCode = ( size_t ) eErrorCode, xTotalLength = 0; /* Only initialised to keep compiler quiet. */
|
|
const char *pcErrorString = NULL;
|
|
int32_t lReturned;
|
|
|
|
/* The total size of the packet to be sent depends on the length of the
|
|
error string. */
|
|
if( xErrorCode < xNumberOfErrorStrings )
|
|
{
|
|
pcErrorString = cErrorStrings[ xErrorCode ];
|
|
|
|
/* This task is going to send using the zero copy interface. The data
|
|
being sent is therefore written directly into a buffer that is passed
|
|
into, rather than copied into, the FreeRTOS_sendto() function. First
|
|
obtain a buffer of adequate length from the IP stack into which the
|
|
error packet will be written. Although a max delay is used, the actual
|
|
delay will be capped to ipconfigMAX_SEND_BLOCK_TIME_TICKS. */
|
|
xTotalLength = strlen( pcErrorString ) + xFixedSizePart;
|
|
pucUDPPayloadBuffer = ( uint8_t * ) FreeRTOS_GetUDPPayloadBuffer( xTotalLength, portMAX_DELAY );
|
|
}
|
|
|
|
if( pucUDPPayloadBuffer != NULL )
|
|
{
|
|
FreeRTOS_printf( ( "Error: %s\n", pcErrorString ) );
|
|
|
|
/* Create error packet: Opcode. */
|
|
pucUDPPayloadBuffer[ 0 ] = 0;
|
|
pucUDPPayloadBuffer[ 1 ] = ( uint8_t ) eError;
|
|
|
|
/* Create error packet: Error code. */
|
|
pucUDPPayloadBuffer[ 2 ] = 0;
|
|
pucUDPPayloadBuffer[ 3 ] = ( uint8_t ) eErrorCode;
|
|
|
|
/* Create error packet: Error string. */
|
|
strcpy( ( ( char * ) &( pucUDPPayloadBuffer[ 4 ] ) ), pcErrorString );
|
|
|
|
/* Pass the buffer into the send function. ulFlags has the
|
|
FREERTOS_ZERO_COPY bit set so the IP stack will take control of the
|
|
buffer rather than copy data out of the buffer. */
|
|
lReturned = FreeRTOS_sendto( xSocket, /* The socket to which the error frame is sent. */
|
|
( void * ) pucUDPPayloadBuffer, /* A pointer to the the data being sent. */
|
|
xTotalLength, /* The length of the data being sent. */
|
|
FREERTOS_ZERO_COPY, /* ulFlags with the FREERTOS_ZERO_COPY bit set. */
|
|
pxClient, /* Where the data is being sent. */
|
|
sizeof( *pxClient ) );
|
|
|
|
if( lReturned == 0 )
|
|
{
|
|
/* The send operation failed, so this task is still responsible
|
|
for the buffer obtained from the IP stack. To ensure the buffer
|
|
is not lost it must either be used again, or, as in this case,
|
|
returned to the IP stack using FreeRTOS_ReleaseUDPPayloadBuffer(). */
|
|
FreeRTOS_ReleaseUDPPayloadBuffer( ( void * ) pucUDPPayloadBuffer );
|
|
}
|
|
else
|
|
{
|
|
/* The send was successful so the IP stack is now managing the
|
|
buffer pointed to by pucUDPPayloadBuffer, and the IP stack will
|
|
return the buffer once it has been sent. */
|
|
}
|
|
}
|
|
}
|
|
|
|
|