in source/device_defender.c [285:559]
static int s_get_metric_report_json(
struct aws_byte_buf *json_out,
struct aws_iotdevice_defender_task *task,
uint64_t report_id,
const struct aws_iotdevice_metric_network_transfer *net_xfer,
const struct aws_array_list *net_conns,
size_t custom_metrics_len,
const struct defender_custom_metric_data *custom_metrics_data) {
int return_value = AWS_OP_ERR;
const char *json_report = NULL;
struct cJSON *root = cJSON_CreateObject();
if (root == NULL) {
goto cleanup;
}
struct cJSON *header = cJSON_CreateObject();
if (header == NULL) {
goto cleanup;
}
cJSON_AddItemToObject(root, "header", header);
if (NULL == cJSON_AddNumberToObject(header, "report_id", (double)report_id)) {
goto cleanup;
}
if (NULL == cJSON_AddStringToObject(header, "version", "1.0")) {
goto cleanup;
}
struct cJSON *metrics = cJSON_CreateObject();
if (metrics == NULL) {
goto cleanup;
}
cJSON_AddItemToObject(root, "metrics", metrics);
struct cJSON *listening_tcp_ports = cJSON_CreateObject();
if (listening_tcp_ports == NULL) {
goto cleanup;
}
cJSON_AddItemToObject(metrics, "listening_tcp_ports", listening_tcp_ports);
struct cJSON *tcp_listen_ports = cJSON_CreateArray();
if (tcp_listen_ports == NULL) {
goto cleanup;
}
cJSON_AddItemToObject(listening_tcp_ports, "ports", tcp_listen_ports);
struct cJSON *tcp_connections = cJSON_CreateObject();
if (tcp_connections == NULL) {
goto cleanup;
}
cJSON_AddItemToObject(metrics, "tcp_connections", tcp_connections);
struct cJSON *established_tcp_conns = cJSON_CreateObject();
if (established_tcp_conns == NULL) {
goto cleanup;
}
cJSON_AddItemToObject(tcp_connections, "established_connections", established_tcp_conns);
struct cJSON *est_connections = cJSON_CreateArray();
if (est_connections == NULL) {
goto cleanup;
}
cJSON_AddItemToObject(established_tcp_conns, "connections", est_connections);
struct cJSON *listening_udp_ports = cJSON_CreateObject();
if (listening_udp_ports == NULL) {
goto cleanup;
}
cJSON_AddItemToObject(metrics, "listening_udp_ports", listening_udp_ports);
struct cJSON *udp_ports = cJSON_CreateArray();
if (udp_ports == NULL) {
goto cleanup;
}
cJSON_AddItemToObject(listening_udp_ports, "ports", udp_ports);
int total_listening_tcp_ports = 0;
int total_established_tcp_conns = 0;
int total_udp_listeners = 0;
const size_t net_conn_sz = aws_array_list_length(net_conns);
for (size_t tcp_index = 0; tcp_index < net_conn_sz; ++tcp_index) {
struct aws_iotdevice_metric_net_connection *net_conn = NULL;
aws_array_list_get_at_ptr(net_conns, (void **)&net_conn, tcp_index);
if (net_conn->state == AWS_IDNCS_ESTABLISHED && net_conn->protocol == AWS_IDNP_TCP) {
total_established_tcp_conns++;
struct cJSON *conn = cJSON_CreateObject();
if (conn == NULL) {
goto cleanup;
}
cJSON_AddItemToArray(est_connections, conn);
if (NULL == cJSON_AddStringToObject(conn, "local_interface", aws_string_c_str(net_conn->local_interface))) {
goto cleanup;
}
if (NULL == cJSON_AddNumberToObject(conn, "local_port", net_conn->local_port)) {
goto cleanup;
}
char remote_addr[22];
snprintf(remote_addr, 22, "%s:%u", aws_string_c_str(net_conn->remote_address), net_conn->remote_port);
if (NULL == cJSON_AddStringToObject(conn, "remote_addr", remote_addr)) {
goto cleanup;
}
} else if (net_conn->state == AWS_IDNCS_LISTEN && net_conn->protocol == AWS_IDNP_TCP) {
total_listening_tcp_ports++;
struct cJSON *conn = cJSON_CreateObject();
if (conn == NULL) {
goto cleanup;
}
cJSON_AddItemToArray(tcp_listen_ports, conn);
if (NULL == cJSON_AddStringToObject(conn, "interface", aws_string_c_str(net_conn->local_interface))) {
goto cleanup;
}
if (NULL == cJSON_AddNumberToObject(conn, "port", net_conn->local_port)) {
goto cleanup;
}
} else if (net_conn->state == AWS_IDNCS_LISTEN && net_conn->protocol == AWS_IDNP_UDP) {
++total_udp_listeners;
struct cJSON *conn = cJSON_CreateObject();
if (conn == NULL) {
goto cleanup;
}
cJSON_AddItemToArray(udp_ports, conn);
if (NULL == cJSON_AddStringToObject(conn, "interface", aws_string_c_str(net_conn->local_interface))) {
goto cleanup;
}
if (NULL == cJSON_AddNumberToObject(conn, "port", net_conn->local_port)) {
goto cleanup;
}
}
}
if (NULL == cJSON_AddNumberToObject(established_tcp_conns, "total", total_established_tcp_conns)) {
goto cleanup;
}
if (NULL == cJSON_AddNumberToObject(listening_tcp_ports, "total", total_listening_tcp_ports)) {
goto cleanup;
}
if (NULL == cJSON_AddNumberToObject(listening_udp_ports, "total", (double)total_udp_listeners)) {
goto cleanup;
}
struct cJSON *network_stats = cJSON_CreateObject();
if (network_stats == NULL) {
goto cleanup;
}
cJSON_AddItemToObject(metrics, "network_stats", network_stats);
if (NULL == cJSON_AddNumberToObject(network_stats, "bytes_in", net_xfer != NULL ? (double)net_xfer->bytes_in : 0)) {
goto cleanup;
}
if (NULL ==
cJSON_AddNumberToObject(network_stats, "bytes_out", net_xfer != NULL ? (double)net_xfer->bytes_out : 0)) {
goto cleanup;
}
if (NULL ==
cJSON_AddNumberToObject(network_stats, "packets_in", net_xfer != NULL ? (double)net_xfer->packets_in : 0)) {
goto cleanup;
}
if (NULL ==
cJSON_AddNumberToObject(network_stats, "packets_out", net_xfer != NULL ? (double)net_xfer->packets_out : 0)) {
goto cleanup;
}
if (custom_metrics_len != 0) {
struct cJSON *custom_metrics = cJSON_CreateObject();
if (NULL == custom_metrics) {
goto cleanup;
}
cJSON_AddItemToObject(root, "custom_metrics", custom_metrics);
size_t list_size = 0;
struct cJSON *array_item = NULL;
struct cJSON *item = NULL;
struct cJSON *json_list = NULL;
struct cJSON *spurious_array_container = NULL;
for (size_t metric_index = 0; metric_index < custom_metrics_len; ++metric_index) {
if (custom_metrics_data[metric_index].callback_result != AWS_OP_SUCCESS) {
/* if the collection of a metric failed, do not output it to the report */
continue;
}
spurious_array_container = cJSON_CreateArray();
if (NULL == spurious_array_container) {
goto cleanup;
}
cJSON_AddItemToObject(
custom_metrics,
aws_string_c_str(custom_metrics_data[metric_index].metric->metric_name),
spurious_array_container);
item = cJSON_CreateObject();
if (NULL == item) {
goto cleanup;
}
cJSON_AddItemToArray(spurious_array_container, item);
switch (custom_metrics_data[metric_index].metric->type) {
case DD_METRIC_NUMBER:
cJSON_AddNumberToObject(item, "number", (double)custom_metrics_data[metric_index].data.number);
break;
case DD_METRIC_NUMBER_LIST:
list_size = aws_array_list_length(&custom_metrics_data[metric_index].data.list);
json_list = cJSON_CreateArray();
if (NULL == json_list) {
goto cleanup;
}
cJSON_AddItemToObject(item, "number_list", json_list);
for (size_t num_index = 0; num_index < list_size; ++num_index) {
int64_t number = 0;
aws_array_list_get_at(&custom_metrics_data[metric_index].data.list, &number, num_index);
array_item = cJSON_CreateNumber((double)number);
cJSON_AddItemToArray(json_list, array_item);
}
break;
case DD_METRIC_STRING_LIST:
list_size = aws_array_list_length(&custom_metrics_data[metric_index].data.list);
json_list = cJSON_CreateArray();
if (NULL == json_list) {
goto cleanup;
}
cJSON_AddItemToObject(item, "string_list", json_list);
for (size_t string_index = 0; string_index < list_size; ++string_index) {
struct aws_string *string_value = NULL;
aws_array_list_get_at(
&custom_metrics_data[metric_index].data.list, &string_value, string_index);
array_item = cJSON_CreateString(aws_string_c_str(string_value));
cJSON_AddItemToArray(json_list, array_item);
}
break;
case DD_METRIC_IP_LIST:
list_size = aws_array_list_length(&custom_metrics_data[metric_index].data.list);
json_list = cJSON_CreateArray();
if (NULL == json_list) {
goto cleanup;
}
cJSON_AddItemToObject(item, "ip_list", json_list);
for (size_t ip_index = 0; ip_index < list_size; ++ip_index) {
struct aws_string *ip_value = NULL;
aws_array_list_get_at(&custom_metrics_data[metric_index].data.list, &ip_value, ip_index);
array_item = cJSON_CreateString(aws_string_c_str(ip_value));
cJSON_AddItemToArray(json_list, array_item);
}
break;
case DD_METRIC_UNKNOWN:
default:
AWS_LOGF_WARN(
AWS_LS_IOTDEVICE_DEFENDER_TASK,
"id=%p: Unknown custom metrics type found during report generation: %d, name %s",
(void *)task,
custom_metrics_data[metric_index].metric->type,
aws_string_c_str(custom_metrics_data[metric_index].metric->metric_name));
continue;
break;
}
}
}
json_report = cJSON_PrintUnformatted(root);
struct aws_byte_cursor json_report_buf = {.len = strlen(json_report) + 1, .ptr = (uint8_t *)json_report};
if (AWS_OP_SUCCESS != aws_byte_buf_init_copy_from_cursor(json_out, task->allocator, json_report_buf)) {
s_invoke_failure_callback(&task->config, false, AWS_ERROR_IOTDEVICE_DEFENDER_REPORT_SERIALIZATION_FAILURE);
return_value = AWS_OP_ERR;
} else {
return_value = AWS_OP_SUCCESS;
}
cleanup:
if (json_report) {
cJSON_free((void *)json_report);
}
if (root) {
cJSON_Delete(root);
}
if (return_value != AWS_OP_SUCCESS) {
aws_raise_error(AWS_ERROR_IOTDEVICE_DEFENDER_REPORT_SERIALIZATION_FAILURE);
}
return return_value;
}