Add custom metrics to defender demo (#507)

Adds custom metrics to the defender demo. The metrics added are a list of the task ids and the stack high water mark.
pull/525/head
Archit Gupta 4 years ago committed by GitHub
parent e61730c9b1
commit c8fa483b68
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -35,18 +35,20 @@
* with another MQTT library. This demo requires using the AWS IoT broker as * with another MQTT library. This demo requires using the AWS IoT broker as
* Device Defender is an AWS service. * Device Defender is an AWS service.
* *
* This demo connects to the AWS IoT broker and subscribes to the device * This demo subscribes to the device defender topics. It then collects metrics
* defender topics. It then collects metrics for the open ports and sockets on * for the open ports and sockets on the device using FreeRTOS+TCP. Additonally
* the device using FreeRTOS+TCP, and generates a device defender report. The * the stack high water mark and task IDs are collected for custom metrics.
* These metrics are used to generate a device defender report. The
* report is then published, and the demo waits for a response from the device * report is then published, and the demo waits for a response from the device
* defender service. Upon receiving the response or timing out, the demo * defender service. Upon receiving an accepted response, the demo finishes.
* finishes. * If the demo receives a rejected response or times out, the demo repeats up to
* a maximum of DEFENDER_MAX_DEMO_LOOP_COUNT times.
* *
* This demo sets the report ID to xTaskGetTickCount(), which may collide if * This demo sets the report ID to xTaskGetTickCount(), which may collide if
* the device is reset. Reports for a Thing with a previously used report ID * the device is reset. Reports for a Thing with a previously used report ID
* will be assumed to be duplicates and discarded by the Device Defender * will be assumed to be duplicates and discarded by the Device Defender
* service. The report ID needs to be unique per report sent with a given * service. The report ID needs to be unique per report sent with a given
* Thing. We recommend using an increasing unique id such as the current * Thing. We recommend using an increasing unique ID such as the current
* timestamp. * timestamp.
*/ */
@ -97,7 +99,7 @@
#define DEFENDER_RESPONSE_WAIT_SECONDS ( 2 ) #define DEFENDER_RESPONSE_WAIT_SECONDS ( 2 )
/** /**
* @brief Name of the report id field in the response from the AWS IoT Device * @brief Name of the report ID field in the response from the AWS IoT Device
* Defender service. * Defender service.
*/ */
#define DEFENDER_RESPONSE_REPORT_ID_FIELD "reportId" #define DEFENDER_RESPONSE_REPORT_ID_FIELD "reportId"
@ -133,8 +135,8 @@ typedef enum
ReportStatusRejected ReportStatusRejected
} ReportStatus_t; } ReportStatus_t;
/** /**
* @brief Each compilation unit that consumes the NetworkContext must define it. * @brief Each compilation unit that consumes the NetworkContext must define it.
* It should contain a single pointer to the type of your desired transport. * It should contain a single pointer to the type of your desired transport.
* When using multiple transports in the same compilation unit, define this pointer as void *. * When using multiple transports in the same compilation unit, define this pointer as void *.
* *
@ -195,6 +197,16 @@ static uint16_t pusOpenUdpPorts[ democonfigOPEN_UDP_PORTS_ARRAY_SIZE ];
*/ */
static Connection_t pxEstablishedConnections[ democonfigESTABLISHED_CONNECTIONS_ARRAY_SIZE ]; static Connection_t pxEstablishedConnections[ democonfigESTABLISHED_CONNECTIONS_ARRAY_SIZE ];
/**
* @brief Array of task statuses, used to generate custom metrics.
*/
static TaskStatus_t pxTaskStatusList[ democonfigCUSTOM_METRICS_TASKS_ARRAY_SIZE ];
/**
* @brief Task numbers custom metric array.
*/
static uint32_t pulCustomMetricsTaskNumbers[ democonfigCUSTOM_METRICS_TASKS_ARRAY_SIZE ];
/** /**
* @brief All the metrics sent in the device defender report. * @brief All the metrics sent in the device defender report.
*/ */
@ -211,9 +223,10 @@ static ReportStatus_t xReportStatus;
static char pcDeviceMetricsJsonReport[ democonfigDEVICE_METRICS_REPORT_BUFFER_SIZE ]; static char pcDeviceMetricsJsonReport[ democonfigDEVICE_METRICS_REPORT_BUFFER_SIZE ];
/** /**
* @brief Report Id sent in the defender report. * @brief Report ID sent in the defender report.
*/ */
static uint32_t ulReportId = 0UL; static uint32_t ulReportId = 0UL;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/** /**
@ -463,7 +476,9 @@ static bool prvCollectDeviceMetrics( void )
{ {
bool xStatus = false; bool xStatus = false;
eMetricsCollectorStatus eMetricsCollectorStatus; eMetricsCollectorStatus eMetricsCollectorStatus;
uint32_t ulNumOpenTcpPorts = 0UL, ulNumOpenUdpPorts = 0UL, ulNumEstablishedConnections = 0UL; uint32_t ulNumOpenTcpPorts = 0UL, ulNumOpenUdpPorts = 0UL, ulNumEstablishedConnections = 0UL, i;
UBaseType_t uxTasksWritten = { 0 };
TaskStatus_t pxTaskStatus = { 0 };
/* Collect bytes and packets sent and received. */ /* Collect bytes and packets sent and received. */
eMetricsCollectorStatus = eGetNetworkStats( &( xNetworkStats ) ); eMetricsCollectorStatus = eGetNetworkStats( &( xNetworkStats ) );
@ -516,6 +531,36 @@ static bool prvCollectDeviceMetrics( void )
} }
} }
/* Collect custom metrics. This demo sends this task's stack high water mark
* as a number type custom metric and the current task IDs as a list of
* numbers type custom metric. */
if( eMetricsCollectorStatus == eMetricsCollectorSuccess )
{
vTaskGetInfo(
/* Query this task. */
NULL,
&pxTaskStatus,
/* Include the stack high water mark value. */
pdTRUE,
/* Don't include the task state in the TaskStatus_t structure. */
0 );
uxTasksWritten = uxTaskGetSystemState( pxTaskStatusList, democonfigCUSTOM_METRICS_TASKS_ARRAY_SIZE, NULL );
if( uxTasksWritten == 0 )
{
eMetricsCollectorStatus = eMetricsCollectorCollectionFailed;
LogError( ( "Failed to collect system state. uxTaskGetSystemState() failed due to insufficient buffer space.",
eMetricsCollectorStatus ) );
}
else
{
for( i = 0; i < uxTasksWritten; i++ )
{
pulCustomMetricsTaskNumbers[ i ] = pxTaskStatusList[ i ].xTaskNumber;
}
}
}
/* Populate device metrics. */ /* Populate device metrics. */
if( eMetricsCollectorStatus == eMetricsCollectorSuccess ) if( eMetricsCollectorStatus == eMetricsCollectorSuccess )
{ {
@ -527,6 +572,9 @@ static bool prvCollectDeviceMetrics( void )
xDeviceMetrics.ulOpenUdpPortsArrayLength = ulNumOpenUdpPorts; xDeviceMetrics.ulOpenUdpPortsArrayLength = ulNumOpenUdpPorts;
xDeviceMetrics.pxEstablishedConnectionsArray = &( pxEstablishedConnections[ 0 ] ); xDeviceMetrics.pxEstablishedConnectionsArray = &( pxEstablishedConnections[ 0 ] );
xDeviceMetrics.ulEstablishedConnectionsArrayLength = ulNumEstablishedConnections; xDeviceMetrics.ulEstablishedConnectionsArrayLength = ulNumEstablishedConnections;
xDeviceMetrics.ulStackHighWaterMark = pxTaskStatus.usStackHighWaterMark;
xDeviceMetrics.pulTaskIdArray = pulCustomMetricsTaskNumbers;
xDeviceMetrics.ulTaskIdArrayLength = uxTasksWritten;
} }
return xStatus; return xStatus;
@ -671,14 +719,14 @@ void prvDefenderDemoTask( void * pvParameters )
* DEFENDER_MAX_DEMO_LOOP_COUNT times. */ * DEFENDER_MAX_DEMO_LOOP_COUNT times. */
do do
{ {
/* Set a report Id to be used. /* Set a report ID to be used.
* *
* !!!NOTE!!! * !!!NOTE!!!
* This demo sets the report ID to xTaskGetTickCount(), which may collide * This demo sets the report ID to xTaskGetTickCount(), which may collide
* if the device is reset. Reports for a Thing with a previously used * if the device is reset. Reports for a Thing with a previously used
* report ID will be assumed to be duplicates and discarded by the Device * report ID will be assumed to be duplicates and discarded by the Device
* Defender service. The report ID needs to be unique per report sent with * Defender service. The report ID needs to be unique per report sent with
* a given Thing. We recommend using an increasing unique id such as the * a given Thing. We recommend using an increasing unique ID such as the
* current timestamp. */ * current timestamp. */
ulReportId = ( uint32_t ) xTaskGetTickCount(); ulReportId = ( uint32_t ) xTaskGetTickCount();

@ -48,7 +48,8 @@
#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 60 ) /* In this simulated case, the stack only has to hold one small structure as the real stack is part of the Win32 thread. */ #define configMINIMAL_STACK_SIZE ( ( unsigned short ) 60 ) /* In this simulated case, the stack only has to hold one small structure as the real stack is part of the Win32 thread. */
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 2048U * 1024U ) ) #define configTOTAL_HEAP_SIZE ( ( size_t ) ( 2048U * 1024U ) )
#define configMAX_TASK_NAME_LEN ( 15 ) #define configMAX_TASK_NAME_LEN ( 15 )
#define configUSE_TRACE_FACILITY 0 #define configUSE_TRACE_FACILITY 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 0
#define configUSE_16_BIT_TICKS 0 #define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1 #define configIDLE_SHOULD_YIELD 1
#define configUSE_CO_ROUTINES 0 #define configUSE_CO_ROUTINES 0
@ -103,15 +104,6 @@
#define INCLUDE_xTimerPendFunctionCall 1 #define INCLUDE_xTimerPendFunctionCall 1
#define INCLUDE_pcTaskGetTaskName 1 #define INCLUDE_pcTaskGetTaskName 1
/* This demo makes use of one or more example stats formatting functions. These
* format the raw data provided by the uxTaskGetSystemState() function in to human
* readable ASCII form. See the notes in the implementation of vTaskList() within
* FreeRTOS/Source/tasks.c for limitations. configUSE_STATS_FORMATTING_FUNCTIONS
* is set to 2 so the formatting functions are included without the stdio.h being
* included in tasks.c. That is because this project defines its own sprintf()
* functions. */
#define configUSE_STATS_FORMATTING_FUNCTIONS 1
/* Assert call defined for debug builds. */ /* Assert call defined for debug builds. */
#ifdef _DEBUG #ifdef _DEBUG
extern void vAssertCalled( const char * pcFile, extern void vAssertCalled( const char * pcFile,

@ -52,4 +52,44 @@
/************ End of logging configuration ****************/ /************ End of logging configuration ****************/
/**
* AWS IoT Device Defender Service supports both long and short names for keys
* in the report sent by a device. For example,
*
* A device defender report using long key names:
* {
* "header": {
* "report_id": 1530304554,
* "version": "1.0"
* },
* "metrics": {
* "network_stats": {
* "bytes_in": 29358693495,
* "bytes_out": 26485035,
* "packets_in": 10013573555,
* "packets_out": 11382615
* }
* }
* }
*
* An equivalent report using short key names:
* {
* "hed": {
* "rid": 1530304554,
* "v": "1.0"
* },
* "met": {
* "ns": {
* "bi": 29358693495,
* "bo": 26485035,
* "pi": 10013573555,
* "po": 11382615
* }
* }
* }
*
* Set to 1 to enable use of long key names in the defender report.
*/
#define DEFENDER_USE_LONG_KEYS 0
#endif /* ifndef DEFENDER_CONFIG_H_ */ #endif /* ifndef DEFENDER_CONFIG_H_ */

@ -261,6 +261,13 @@ extern void vLoggingPrintf( const char * pcFormatString,
*/ */
#define democonfigESTABLISHED_CONNECTIONS_ARRAY_SIZE 10 #define democonfigESTABLISHED_CONNECTIONS_ARRAY_SIZE 10
/**
* @brief Size of the task numbers array.
*
* This must be at least the number of tasks used.
*/
#define democonfigCUSTOM_METRICS_TASKS_ARRAY_SIZE 10
/** /**
* @brief Size of the buffer which contains the generated device defender report. * @brief Size of the buffer which contains the generated device defender report.
* *

@ -43,9 +43,6 @@
#include "FreeRTOS.h" #include "FreeRTOS.h"
#include "FreeRTOS_IP.h" #include "FreeRTOS_IP.h"
/* FreeRTOS+TCP tcp_netstat utility include. */
#include "tcp_netstat.h"
/* Demo config. */ /* Demo config. */
#include "demo_config.h" #include "demo_config.h"

@ -36,6 +36,9 @@
/* Demo config. */ /* Demo config. */
#include "demo_config.h" #include "demo_config.h"
/* Device Defender Client Library. */
#include "defender.h"
/* Interface include. */ /* Interface include. */
#include "report_builder.h" #include "report_builder.h"
@ -50,53 +53,68 @@
/* Formats used to generate the JSON report. */ /* Formats used to generate the JSON report. */
#define reportbuilderJSON_PORT_OBJECT_FORMAT \ #define reportbuilderJSON_PORT_OBJECT_FORMAT \
"{" \ "{" \
"\"port\": %u" \ "\"%s\": %u" \
"}," "},"
#define reportbuilderJSON_CONNECTION_OBJECT_FORMAT \ #define reportbuilderJSON_CONNECTION_OBJECT_FORMAT \
"{" \ "{" \
"\"local_port\": %u," \ "\"%s\": %u," \
"\"remote_addr\": \"%u.%u.%u.%u:%u\"" \ "\"%s\": \"%u.%u.%u.%u:%u\"" \
"}," "},"
#define reportbuilderJSON_REPORT_FORMAT_PART1 \ #define reportbuilderJSON_REPORT_FORMAT_PART1 \
"{" \ "{" \
"\"header\": {" \ "\"%s\": {" \
"\"report_id\": %u," \ "\"%s\": %u," \
"\"version\": \"%u.%u\"" \ "\"%s\": \"%u.%u\"" \
"}," \ "}," \
"\"metrics\": {" \ "\"%s\": {" \
"\"listening_tcp_ports\": {" \ "\"%s\": {" \
"\"ports\": " "\"%s\": "
#define reportbuilderJSON_REPORT_FORMAT_PART2 \ #define reportbuilderJSON_REPORT_FORMAT_PART2 \
"," \ "," \
"\"total\": %u" \ "\"%s\": %u" \
"}," \ "}," \
"\"listening_udp_ports\": {" \ "\"%s\": {" \
"\"ports\": " "\"%s\": "
#define reportbuilderJSON_REPORT_FORMAT_PART3 \ #define reportbuilderJSON_REPORT_FORMAT_PART3 \
"," \ "," \
"\"total\": %u" \ "\"%s\": %u" \
"}," \ "}," \
"\"network_stats\": {" \ "\"%s\": {" \
"\"bytes_in\": %u," \ "\"%s\": %u," \
"\"bytes_out\": %u," \ "\"%s\": %u," \
"\"packets_in\": %u," \ "\"%s\": %u," \
"\"packets_out\": %u" \ "\"%s\": %u" \
"}," \ "}," \
"\"tcp_connections\": {" \ "\"%s\": {" \
"\"established_connections\": {" \ "\"%s\": {" \
"\"connections\": " "\"%s\": "
#define reportbuilderJSON_REPORT_FORMAT_PART4 \ #define reportbuilderJSON_REPORT_FORMAT_PART4 \
"," \ "," \
"\"total\": %u" \ "\"%s\": %u" \
"}" \
"}" \ "}" \
"}," \
"\"%s\": {" \
"\"stack_high_water_mark\": [" \
"{" \
"\"%s\": %u" \
"}" \
"]," \
"\"task_numbers\": [" \
"{" \
"\"%s\": "
#define reportbuilderJSON_REPORT_FORMAT_PART5 \
"}" \ "}" \
"]" \
"}" \ "}" \
"}" "}"
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/** /**
@ -158,6 +176,24 @@ static eReportBuilderStatus prvWriteConnectionsArray( char * pcBuffer,
const Connection_t * pxConnectionsArray, const Connection_t * pxConnectionsArray,
uint32_t ulConnectionsArrayLength, uint32_t ulConnectionsArrayLength,
uint32_t * pulOutCharsWritten ); uint32_t * pulOutCharsWritten );
/**
* @brief Write task ID array to the given buffer as a JSON array.
*
* @param[in] pcBuffer The buffer to write the array of task IDs.
* @param[in] ulBufferLength The length of the buffer.
* @param[in] pulTaskIdArray The array containing the task IDs.
* @param[in] pulTaskIdArrayLength Length of the pulTaskIdsArray array.
* @param[out] pulOutCharsWritten Number of characters written to the buffer.
*
* @return #ReportBuilderSuccess if the array is successfully written;
* #ReportBuilderBufferTooSmall if the buffer cannot hold the full array.
*/
static eReportBuilderStatus prvWriteTaskIdArray( char * pcBuffer,
uint32_t ulBufferLength,
const uint32_t * pulTaskIdArray,
uint32_t pulTaskIdArrayLength,
uint32_t * pulOutCharsWritten );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static eReportBuilderStatus prvWritePortsArray( char * pcBuffer, static eReportBuilderStatus prvWritePortsArray( char * pcBuffer,
@ -168,7 +204,7 @@ static eReportBuilderStatus prvWritePortsArray( char * pcBuffer,
{ {
char * pcCurrentWritePos = pcBuffer; char * pcCurrentWritePos = pcBuffer;
uint32_t i, ulRemainingBufferLength = ulBufferLength; uint32_t i, ulRemainingBufferLength = ulBufferLength;
int32_t ulCharactersWritten; int32_t lCharactersWritten;
eReportBuilderStatus eStatus = eReportBuilderSuccess; eReportBuilderStatus eStatus = eReportBuilderSuccess;
configASSERT( pcBuffer != NULL ); configASSERT( pcBuffer != NULL );
@ -190,20 +226,20 @@ static eReportBuilderStatus prvWritePortsArray( char * pcBuffer,
/* Write the array elements. */ /* Write the array elements. */
for( i = 0; ( ( i < ulOpenPortsArrayLength ) && ( eStatus == eReportBuilderSuccess ) ); i++ ) for( i = 0; ( ( i < ulOpenPortsArrayLength ) && ( eStatus == eReportBuilderSuccess ) ); i++ )
{ {
ulCharactersWritten = snprintf( pcCurrentWritePos, lCharactersWritten = snprintf( pcCurrentWritePos,
ulRemainingBufferLength, ulRemainingBufferLength,
reportbuilderJSON_PORT_OBJECT_FORMAT, reportbuilderJSON_PORT_OBJECT_FORMAT,
pusOpenPortsArray[ i ] ); DEFENDER_REPORT_PORT_KEY,
pusOpenPortsArray[ i ] );
if( !reportbuilderSNPRINTF_SUCCESS( ulCharactersWritten, ulRemainingBufferLength ) ) if( !reportbuilderSNPRINTF_SUCCESS( lCharactersWritten, ulRemainingBufferLength ) )
{ {
eStatus = eReportBuilderBufferTooSmall; eStatus = eReportBuilderBufferTooSmall;
break;
} }
else else
{ {
ulRemainingBufferLength -= ( uint32_t ) ulCharactersWritten; ulRemainingBufferLength -= ( uint32_t ) lCharactersWritten;
pcCurrentWritePos += ulCharactersWritten; pcCurrentWritePos += lCharactersWritten;
} }
} }
@ -222,6 +258,7 @@ static eReportBuilderStatus prvWritePortsArray( char * pcBuffer,
*pcCurrentWritePos = reportbuilderJSON_ARRAY_CLOSE_MARKER; *pcCurrentWritePos = reportbuilderJSON_ARRAY_CLOSE_MARKER;
ulRemainingBufferLength -= 1; ulRemainingBufferLength -= 1;
pcCurrentWritePos += 1; pcCurrentWritePos += 1;
*pulOutCharsWritten = ulBufferLength - ulRemainingBufferLength;
} }
else else
{ {
@ -229,11 +266,6 @@ static eReportBuilderStatus prvWritePortsArray( char * pcBuffer,
} }
} }
if( eStatus == eReportBuilderSuccess )
{
*pulOutCharsWritten = ulBufferLength - ulRemainingBufferLength;
}
return eStatus; return eStatus;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -246,7 +278,7 @@ static eReportBuilderStatus prvWriteConnectionsArray( char * pcBuffer,
{ {
char * pcCurrentWritePos = pcBuffer; char * pcCurrentWritePos = pcBuffer;
uint32_t i, ulRemainingBufferLength = ulBufferLength; uint32_t i, ulRemainingBufferLength = ulBufferLength;
int32_t ulCharactersWritten; int32_t lCharactersWritten;
eReportBuilderStatus eStatus = eReportBuilderSuccess; eReportBuilderStatus eStatus = eReportBuilderSuccess;
const Connection_t * pxConn; const Connection_t * pxConn;
@ -270,25 +302,26 @@ static eReportBuilderStatus prvWriteConnectionsArray( char * pcBuffer,
for( i = 0; ( ( i < ulConnectionsArrayLength ) && ( eStatus == eReportBuilderSuccess ) ); i++ ) for( i = 0; ( ( i < ulConnectionsArrayLength ) && ( eStatus == eReportBuilderSuccess ) ); i++ )
{ {
pxConn = &( pxConnectionsArray[ i ] ); pxConn = &( pxConnectionsArray[ i ] );
ulCharactersWritten = snprintf( pcCurrentWritePos, lCharactersWritten = snprintf( pcCurrentWritePos,
ulRemainingBufferLength, ulRemainingBufferLength,
reportbuilderJSON_CONNECTION_OBJECT_FORMAT, reportbuilderJSON_CONNECTION_OBJECT_FORMAT,
pxConn->usLocalPort, DEFENDER_REPORT_LOCAL_PORT_KEY,
( pxConn->ulRemoteIp >> 24 ) & 0xFF, pxConn->usLocalPort,
( pxConn->ulRemoteIp >> 16 ) & 0xFF, DEFENDER_REPORT_REMOTE_ADDR_KEY,
( pxConn->ulRemoteIp >> 8 ) & 0xFF, ( pxConn->ulRemoteIp >> 24 ) & 0xFF,
( pxConn->ulRemoteIp ) & 0xFF, ( pxConn->ulRemoteIp >> 16 ) & 0xFF,
pxConn->usRemotePort ); ( pxConn->ulRemoteIp >> 8 ) & 0xFF,
( pxConn->ulRemoteIp ) & 0xFF,
if( !reportbuilderSNPRINTF_SUCCESS( ulCharactersWritten, ulRemainingBufferLength ) ) pxConn->usRemotePort );
if( !reportbuilderSNPRINTF_SUCCESS( lCharactersWritten, ulRemainingBufferLength ) )
{ {
eStatus = eReportBuilderBufferTooSmall; eStatus = eReportBuilderBufferTooSmall;
break;
} }
else else
{ {
ulRemainingBufferLength -= ulCharactersWritten; ulRemainingBufferLength -= lCharactersWritten;
pcCurrentWritePos += ulCharactersWritten; pcCurrentWritePos += lCharactersWritten;
} }
} }
@ -307,6 +340,7 @@ static eReportBuilderStatus prvWriteConnectionsArray( char * pcBuffer,
*pcCurrentWritePos = reportbuilderJSON_ARRAY_CLOSE_MARKER; *pcCurrentWritePos = reportbuilderJSON_ARRAY_CLOSE_MARKER;
ulRemainingBufferLength -= 1; ulRemainingBufferLength -= 1;
pcCurrentWritePos += 1; pcCurrentWritePos += 1;
*pulOutCharsWritten = ulBufferLength - ulRemainingBufferLength;
} }
else else
{ {
@ -314,9 +348,77 @@ static eReportBuilderStatus prvWriteConnectionsArray( char * pcBuffer,
} }
} }
return eStatus;
}
/*-----------------------------------------------------------*/
static eReportBuilderStatus prvWriteTaskIdArray( char * pcBuffer,
uint32_t ulBufferLength,
const uint32_t * pulTaskIdArray,
uint32_t pulTaskIdArrayLength,
uint32_t * pulOutCharsWritten )
{
char * pcCurrentWritePos = pcBuffer;
uint32_t i, ulRemainingBufferLength = ulBufferLength;
int32_t lCharactersWritten;
eReportBuilderStatus eStatus = eReportBuilderSuccess;
configASSERT( pcBuffer != NULL );
configASSERT( pulTaskIdArray != NULL );
configASSERT( pulOutCharsWritten != NULL );
/* Write the JSON array open marker. */
if( ulRemainingBufferLength > 1 )
{
*pcCurrentWritePos = reportbuilderJSON_ARRAY_OPEN_MARKER;
ulRemainingBufferLength -= 1;
pcCurrentWritePos += 1;
}
else
{
eStatus = eReportBuilderBufferTooSmall;
}
/* Write the array elements. */
for( i = 0; ( ( i < pulTaskIdArrayLength ) && ( eStatus == eReportBuilderSuccess ) ); i++ )
{
lCharactersWritten = snprintf( pcCurrentWritePos,
ulRemainingBufferLength,
"%u,",
pulTaskIdArray[ i ] );
if( !reportbuilderSNPRINTF_SUCCESS( lCharactersWritten, ulRemainingBufferLength ) )
{
eStatus = eReportBuilderBufferTooSmall;
}
else
{
ulRemainingBufferLength -= ( uint32_t ) lCharactersWritten;
pcCurrentWritePos += lCharactersWritten;
}
}
if( eStatus == eReportBuilderSuccess ) if( eStatus == eReportBuilderSuccess )
{ {
*pulOutCharsWritten = ulBufferLength - ulRemainingBufferLength; /* Discard the last comma. */
if( pulTaskIdArrayLength > 0 )
{
pcCurrentWritePos -= 1;
ulRemainingBufferLength += 1;
}
/* Write the JSON array close marker. */
if( ulRemainingBufferLength > 1 )
{
*pcCurrentWritePos = reportbuilderJSON_ARRAY_CLOSE_MARKER;
ulRemainingBufferLength -= 1;
pcCurrentWritePos += 1;
*pulOutCharsWritten = ulBufferLength - ulRemainingBufferLength;
}
else
{
eStatus = eReportBuilderBufferTooSmall;
}
} }
return eStatus; return eStatus;
@ -332,9 +434,10 @@ eReportBuilderStatus eGenerateJsonReport( char * pcBuffer,
uint32_t * pulOutReportLength ) uint32_t * pulOutReportLength )
{ {
char * pcCurrentWritePos = pcBuffer; char * pcCurrentWritePos = pcBuffer;
uint32_t ulRemainingBufferLength = ulBufferLength, bufferWritten; uint32_t ulRemainingBufferLength = ulBufferLength;
uint32_t bufferWritten;
eReportBuilderStatus eStatus = eReportBuilderSuccess; eReportBuilderStatus eStatus = eReportBuilderSuccess;
int32_t ulCharactersWritten; int32_t lCharactersWritten;
configASSERT( pcBuffer != NULL ); configASSERT( pcBuffer != NULL );
configASSERT( pxMetrics != NULL ); configASSERT( pxMetrics != NULL );
@ -358,22 +461,29 @@ eReportBuilderStatus eGenerateJsonReport( char * pcBuffer,
/* Write part1. */ /* Write part1. */
if( eStatus == eReportBuilderSuccess ) if( eStatus == eReportBuilderSuccess )
{ {
ulCharactersWritten = snprintf( pcCurrentWritePos, lCharactersWritten = snprintf( pcCurrentWritePos,
ulRemainingBufferLength, ulRemainingBufferLength,
reportbuilderJSON_REPORT_FORMAT_PART1, reportbuilderJSON_REPORT_FORMAT_PART1,
ulReportId, DEFENDER_REPORT_HEADER_KEY,
ulMajorReportVersion, DEFENDER_REPORT_ID_KEY,
ulMinorReportVersion ); ulReportId,
DEFENDER_REPORT_VERSION_KEY,
if( !reportbuilderSNPRINTF_SUCCESS( ulCharactersWritten, ulRemainingBufferLength ) ) ulMajorReportVersion,
ulMinorReportVersion,
DEFENDER_REPORT_METRICS_KEY,
DEFENDER_REPORT_TCP_LISTENING_PORTS_KEY,
DEFENDER_REPORT_PORTS_KEY
);
if( !reportbuilderSNPRINTF_SUCCESS( lCharactersWritten, ulRemainingBufferLength ) )
{ {
LogError( ( "Failed to write part 1." ) ); LogError( ( "Failed to write part 1." ) );
eStatus = eReportBuilderBufferTooSmall; eStatus = eReportBuilderBufferTooSmall;
} }
else else
{ {
ulRemainingBufferLength -= ulCharactersWritten; ulRemainingBufferLength -= lCharactersWritten;
pcCurrentWritePos += ulCharactersWritten; pcCurrentWritePos += lCharactersWritten;
} }
} }
@ -400,20 +510,24 @@ eReportBuilderStatus eGenerateJsonReport( char * pcBuffer,
/* Write part2. */ /* Write part2. */
if( eStatus == eReportBuilderSuccess ) if( eStatus == eReportBuilderSuccess )
{ {
ulCharactersWritten = snprintf( pcCurrentWritePos, lCharactersWritten = snprintf( pcCurrentWritePos,
ulRemainingBufferLength, ulRemainingBufferLength,
reportbuilderJSON_REPORT_FORMAT_PART2, reportbuilderJSON_REPORT_FORMAT_PART2,
pxMetrics->ulOpenTcpPortsArrayLength ); DEFENDER_REPORT_TOTAL_KEY,
pxMetrics->ulOpenTcpPortsArrayLength,
if( !reportbuilderSNPRINTF_SUCCESS( ulCharactersWritten, ulRemainingBufferLength ) ) DEFENDER_REPORT_UDP_LISTENING_PORTS_KEY,
DEFENDER_REPORT_PORTS_KEY
);
if( !reportbuilderSNPRINTF_SUCCESS( lCharactersWritten, ulRemainingBufferLength ) )
{ {
LogError( ( "Failed to write part 2." ) ); LogError( ( "Failed to write part 2." ) );
eStatus = eReportBuilderBufferTooSmall; eStatus = eReportBuilderBufferTooSmall;
} }
else else
{ {
ulRemainingBufferLength -= ulCharactersWritten; ulRemainingBufferLength -= lCharactersWritten;
pcCurrentWritePos += ulCharactersWritten; pcCurrentWritePos += lCharactersWritten;
} }
} }
@ -440,24 +554,34 @@ eReportBuilderStatus eGenerateJsonReport( char * pcBuffer,
/* Write part3. */ /* Write part3. */
if( eStatus == eReportBuilderSuccess ) if( eStatus == eReportBuilderSuccess )
{ {
ulCharactersWritten = snprintf( pcCurrentWritePos, lCharactersWritten = snprintf( pcCurrentWritePos,
ulRemainingBufferLength, ulRemainingBufferLength,
reportbuilderJSON_REPORT_FORMAT_PART3, reportbuilderJSON_REPORT_FORMAT_PART3,
pxMetrics->ulOpenUdpPortsArrayLength, DEFENDER_REPORT_TOTAL_KEY,
pxMetrics->pxNetworkStats->ulBytesReceived, pxMetrics->ulOpenUdpPortsArrayLength,
pxMetrics->pxNetworkStats->ulBytesSent, DEFENDER_REPORT_NETWORK_STATS_KEY,
pxMetrics->pxNetworkStats->ulPacketsReceived, DEFENDER_REPORT_BYTES_IN_KEY,
pxMetrics->pxNetworkStats->ulPacketsSent ); pxMetrics->pxNetworkStats->ulBytesReceived,
DEFENDER_REPORT_BYTES_OUT_KEY,
if( !reportbuilderSNPRINTF_SUCCESS( ulCharactersWritten, ulRemainingBufferLength ) ) pxMetrics->pxNetworkStats->ulBytesSent,
DEFENDER_REPORT_PKTS_IN_KEY,
pxMetrics->pxNetworkStats->ulPacketsReceived,
DEFENDER_REPORT_PKTS_OUT_KEY,
pxMetrics->pxNetworkStats->ulPacketsSent,
DEFENDER_REPORT_TCP_CONNECTIONS_KEY,
DEFENDER_REPORT_ESTABLISHED_CONNECTIONS_KEY,
DEFENDER_REPORT_CONNECTIONS_KEY
);
if( !reportbuilderSNPRINTF_SUCCESS( lCharactersWritten, ulRemainingBufferLength ) )
{ {
LogError( ( "Failed to write part 3." ) ); LogError( ( "Failed to write part 3." ) );
eStatus = eReportBuilderBufferTooSmall; eStatus = eReportBuilderBufferTooSmall;
} }
else else
{ {
ulRemainingBufferLength -= ulCharactersWritten; ulRemainingBufferLength -= lCharactersWritten;
pcCurrentWritePos += ulCharactersWritten; pcCurrentWritePos += lCharactersWritten;
} }
} }
@ -484,26 +608,67 @@ eReportBuilderStatus eGenerateJsonReport( char * pcBuffer,
/* Write part4. */ /* Write part4. */
if( eStatus == eReportBuilderSuccess ) if( eStatus == eReportBuilderSuccess )
{ {
ulCharactersWritten = snprintf( pcCurrentWritePos, lCharactersWritten = snprintf( pcCurrentWritePos,
ulRemainingBufferLength, ulRemainingBufferLength,
reportbuilderJSON_REPORT_FORMAT_PART4, reportbuilderJSON_REPORT_FORMAT_PART4,
pxMetrics->ulEstablishedConnectionsArrayLength ); DEFENDER_REPORT_TOTAL_KEY,
pxMetrics->ulEstablishedConnectionsArrayLength,
if( !reportbuilderSNPRINTF_SUCCESS( ulCharactersWritten, ulRemainingBufferLength ) ) DEFENDER_REPORT_CUSTOM_METRICS_KEY,
DEFENDER_REPORT_NUMBER_KEY,
pxMetrics->ulStackHighWaterMark,
DEFENDER_REPORT_NUMBER_LIST_KEY
);
if( !reportbuilderSNPRINTF_SUCCESS( lCharactersWritten, ulRemainingBufferLength ) )
{ {
LogError( ( "Failed to write part 4." ) ); LogError( ( "Failed to write part 4." ) );
eStatus = eReportBuilderBufferTooSmall; eStatus = eReportBuilderBufferTooSmall;
} }
else else
{ {
ulRemainingBufferLength -= ulCharactersWritten; ulRemainingBufferLength -= lCharactersWritten;
pcCurrentWritePos += ulCharactersWritten; pcCurrentWritePos += lCharactersWritten;
}
}
/* Write task ids array. */
if( eStatus == eReportBuilderSuccess )
{
eStatus = prvWriteTaskIdArray( pcCurrentWritePos,
ulRemainingBufferLength,
pxMetrics->pulTaskIdArray,
pxMetrics->ulTaskIdArrayLength,
&( bufferWritten ) );
if( eStatus == eReportBuilderSuccess )
{
pcCurrentWritePos += bufferWritten;
ulRemainingBufferLength -= bufferWritten;
}
else
{
LogError( ( "Failed to write task ID array." ) );
} }
} }
/* Write part5. */
if( eStatus == eReportBuilderSuccess ) if( eStatus == eReportBuilderSuccess )
{ {
*pulOutReportLength = ulBufferLength - ulRemainingBufferLength; lCharactersWritten = snprintf( pcCurrentWritePos,
ulRemainingBufferLength,
reportbuilderJSON_REPORT_FORMAT_PART5 );
if( !reportbuilderSNPRINTF_SUCCESS( lCharactersWritten, ulRemainingBufferLength ) )
{
LogError( ( "Failed to write part 5." ) );
eStatus = eReportBuilderBufferTooSmall;
}
else
{
ulRemainingBufferLength -= lCharactersWritten;
pcCurrentWritePos += lCharactersWritten;
*pulOutReportLength = ulBufferLength - ulRemainingBufferLength;
}
} }
return eStatus; return eStatus;

@ -41,7 +41,13 @@ typedef enum
} eReportBuilderStatus; } eReportBuilderStatus;
/** /**
* @brief Represents metrics to be included in the report. * @brief Represents metrics to be included in the report, including custom metrics.
*
* This demo demonstrates the use of the stack high water mark and list of
* running task ids as custom metrics sent to AWS IoT Device Defender service.
*
* For more information on custom metrics, refer to the following AWS document:
* https://docs.aws.amazon.com/iot/latest/developerguide/dd-detect-custom-metrics.html
*/ */
typedef struct ReportMetrics typedef struct ReportMetrics
{ {
@ -52,6 +58,10 @@ typedef struct ReportMetrics
uint32_t ulOpenUdpPortsArrayLength; uint32_t ulOpenUdpPortsArrayLength;
Connection_t * pxEstablishedConnectionsArray; Connection_t * pxEstablishedConnectionsArray;
uint32_t ulEstablishedConnectionsArrayLength; uint32_t ulEstablishedConnectionsArrayLength;
/* Custom metrics */
uint32_t ulStackHighWaterMark;
uint32_t * pulTaskIdArray;
uint32_t ulTaskIdArrayLength;
} ReportMetrics_t; } ReportMetrics_t;
/** /**

@ -1 +1 @@
Subproject commit e15db4c22cfdd534d1e0693cdbdf467c7b09e897 Subproject commit ce98843504b037a81fbfbccd90d90d6f2bb1f417
Loading…
Cancel
Save