Skip to content

Commit 38e45e4

Browse files
committed
set metrics for mqtt3to5 adapter
1 parent 86fc54f commit 38e45e4

5 files changed

Lines changed: 231 additions & 9 deletions

File tree

include/aws/mqtt/private/client_impl_shared.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,6 @@ struct aws_mqtt_iot_sdk_metrics_storage {
147147
};
148148

149149
/* IoT SDK Metrics */
150-
151-
// TODO: the function will zero out metrics_storage, properly deallocate the storage before pass in
152150
AWS_MQTT_API int aws_mqtt_iot_sdk_metrics_storage_init(
153151
struct aws_mqtt_iot_sdk_metrics_storage *metrics_storage,
154152
struct aws_allocator *allocator,

source/client_impl_shared.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,8 +258,6 @@ int aws_mqtt_iot_sdk_metrics_storage_init(
258258
return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
259259
}
260260

261-
AWS_ZERO_STRUCT(*metrics_storage);
262-
263261
if (metrics_options == NULL) {
264262
return AWS_OP_SUCCESS;
265263
}

source/v5/mqtt5_to_mqtt3_adapter.c

Lines changed: 115 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2779,13 +2779,123 @@ static int s_aws_mqtt_client_connection_5_get_stats(
27792779
return AWS_OP_SUCCESS;
27802780
}
27812781

2782+
struct aws_mqtt_set_metrics_task {
2783+
struct aws_task task;
2784+
struct aws_allocator *allocator;
2785+
struct aws_mqtt_client_connection_5_impl *adapter;
2786+
2787+
struct aws_mqtt_iot_sdk_metrics_storage *metrics_storage;
2788+
};
2789+
2790+
static void s_aws_mqtt_set_metrics_task_destroy(struct aws_mqtt_set_metrics_task *task) {
2791+
if (task == NULL) {
2792+
return;
2793+
}
2794+
2795+
aws_mqtt_iot_sdk_metrics_storage_clean_up(task->metrics_storage);
2796+
2797+
aws_mem_release(task->allocator, task);
2798+
}
2799+
2800+
static void s_set_metrics_task_fn(struct aws_task *task, void *arg, enum aws_task_status status) {
2801+
(void)task;
2802+
2803+
struct aws_mqtt_set_metrics_task *set_task = arg;
2804+
struct aws_mqtt_client_connection_5_impl *adapter = set_task->adapter;
2805+
if (status != AWS_TASK_STATUS_RUN_READY) {
2806+
goto done;
2807+
}
2808+
2809+
/* we're in the mqtt5 client's event loop; it's safe to access internal state */
2810+
struct aws_mqtt5_packet_connect_storage *old_connect = adapter->client->config->connect;
2811+
2812+
/*
2813+
* Packet storage stores binary data in a single buffer. The safest way to replace some binary data is
2814+
* to make a new storage from the old storage, deleting the old storage after construction is complete.
2815+
*/
2816+
struct aws_mqtt5_packet_connect_view new_connect_view = old_connect->storage_view;
2817+
2818+
if (set_task->metrics_storage) {
2819+
new_connect_view.metrics = &set_task->metrics_storage->storage_view;
2820+
} else {
2821+
new_connect_view.metrics = NULL;
2822+
}
2823+
2824+
if (aws_mqtt5_packet_connect_view_validate(&new_connect_view)) {
2825+
AWS_LOGF_ERROR(
2826+
AWS_LS_MQTT5_TO_MQTT3_ADAPTER, "id=%p: mqtt3-to-5-adapter - invalid CONNECT metrics", (void *)adapter);
2827+
goto done;
2828+
}
2829+
2830+
struct aws_mqtt5_packet_connect_storage *new_connect =
2831+
aws_mem_calloc(adapter->allocator, 1, sizeof(struct aws_mqtt5_packet_connect_storage));
2832+
2833+
if (aws_mqtt5_packet_connect_storage_init(new_connect, adapter->allocator, &new_connect_view)) {
2834+
aws_mem_release(adapter->allocator, new_connect);
2835+
goto done;
2836+
}
2837+
2838+
adapter->client->config->connect = new_connect;
2839+
aws_mqtt5_packet_connect_storage_clean_up(old_connect);
2840+
aws_mem_release(old_connect->allocator, old_connect);
2841+
2842+
done:
2843+
2844+
aws_ref_count_release(&adapter->internal_refs);
2845+
2846+
s_aws_mqtt_set_metrics_task_destroy(set_task);
2847+
}
2848+
2849+
static struct aws_mqtt_set_metrics_task *s_aws_mqtt_set_metrics_task_new(
2850+
struct aws_allocator *allocator,
2851+
struct aws_mqtt_client_connection_5_impl *adapter,
2852+
const struct aws_mqtt_iot_sdk_metrics *metrics) {
2853+
2854+
struct aws_mqtt_set_metrics_task *set_task = aws_mem_calloc(allocator, 1, sizeof(struct aws_mqtt_set_metrics_task));
2855+
if (set_task == NULL) {
2856+
return NULL;
2857+
}
2858+
2859+
aws_task_init(&set_task->task, s_set_metrics_task_fn, (void *)set_task, "SetMetricsTask");
2860+
set_task->allocator = allocator;
2861+
set_task->adapter = (struct aws_mqtt_client_connection_5_impl *)aws_ref_count_acquire(&adapter->internal_refs);
2862+
2863+
if (metrics != NULL) {
2864+
set_task->metrics_storage = aws_mem_calloc(allocator, 1, sizeof(struct aws_mqtt_iot_sdk_metrics_storage));
2865+
if (aws_mqtt_iot_sdk_metrics_storage_init(set_task->metrics_storage, allocator, metrics)) {
2866+
aws_ref_count_release(&adapter->internal_refs);
2867+
aws_mem_release(allocator, set_task);
2868+
return NULL;
2869+
}
2870+
}
2871+
2872+
return set_task;
2873+
}
2874+
27822875
static int s_aws_mqtt_client_connection_5_set_metrics(void *impl, const struct aws_mqtt_iot_sdk_metrics *metrics) {
2783-
(void)impl;
2784-
(void)metrics;
2876+
struct aws_mqtt_client_connection_5_impl *adapter = impl;
27852877

2786-
/* MQTT5 adapter does not support metrics configuration */
2787-
AWS_LOGF_WARN(AWS_LS_MQTT5_TO_MQTT3_ADAPTER, "MQTT5 adapter does not support metrics configuration");
2788-
return aws_raise_error(AWS_ERROR_UNSUPPORTED_OPERATION);
2878+
if (aws_mqtt_validate_iot_sdk_metrics_utf8(metrics)) {
2879+
AWS_LOGF_DEBUG(
2880+
AWS_LS_MQTT5_TO_MQTT3_ADAPTER, "id=%p: Invalid utf8 or forbidden codepoints in metrics.", (void *)adapter);
2881+
return aws_raise_error(AWS_ERROR_INVALID_UTF8);
2882+
}
2883+
2884+
struct aws_mqtt_set_metrics_task *task = s_aws_mqtt_set_metrics_task_new(adapter->allocator, adapter, metrics);
2885+
if (task == NULL) {
2886+
int error_code = aws_last_error();
2887+
AWS_LOGF_ERROR(
2888+
AWS_LS_MQTT5_TO_MQTT3_ADAPTER,
2889+
"id=%p: failed to create set metrics task, error code %d(%s)",
2890+
(void *)adapter,
2891+
error_code,
2892+
aws_error_debug_str(error_code));
2893+
return AWS_OP_ERR;
2894+
}
2895+
2896+
aws_event_loop_schedule_task_now(adapter->loop, &task->task);
2897+
2898+
return AWS_OP_SUCCESS;
27892899
}
27902900

27912901
static uint16_t s_aws_mqtt_5_resubscribe_existing_topics(

tests/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,9 @@ add_test_case(mqtt5to3_adapter_resubscribe_something)
458458
add_test_case(mqtt5to3_adapter_subscribe_single_null_suback)
459459
add_test_case(mqtt5to3_adapter_subscribe_multi_null_suback)
460460
add_test_case(mqtt5to3_adapter_operation_callbacks_after_shutdown)
461+
add_test_case(mqtt5to3_adapter_set_metrics_valid)
462+
add_test_case(mqtt5to3_adapter_set_metrics_null)
463+
add_test_case(mqtt5to3_adapter_set_metrics_invalid_utf8_library)
461464

462465
add_test_case(mqtt_subscription_set_add_empty_not_subbed)
463466
add_test_case(mqtt_subscription_set_add_single_path)

tests/v5/mqtt5_to_mqtt3_adapter_tests.c

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4406,3 +4406,116 @@ static int s_mqtt5to3_adapter_operation_callbacks_after_shutdown_fn(struct aws_a
44064406
AWS_TEST_CASE(
44074407
mqtt5to3_adapter_operation_callbacks_after_shutdown,
44084408
s_mqtt5to3_adapter_operation_callbacks_after_shutdown_fn)
4409+
4410+
/**
4411+
* Test that aws_mqtt_client_connection_set_metrics works correctly with valid metrics
4412+
*/
4413+
static int s_mqtt5to3_adapter_connection_set_metrics_valid_fn(struct aws_allocator *allocator, void *ctx) {
4414+
(void)ctx;
4415+
4416+
aws_mqtt_library_init(allocator);
4417+
4418+
struct mqtt5_client_test_options test_options;
4419+
aws_mqtt5_client_test_init_default_options(&test_options);
4420+
4421+
struct aws_mqtt5_client_mqtt5_mock_test_fixture_options test_fixture_options = {
4422+
.client_options = &test_options.client_options,
4423+
.server_function_table = &test_options.server_function_table,
4424+
};
4425+
4426+
struct aws_mqtt5_to_mqtt3_adapter_test_fixture fixture;
4427+
ASSERT_SUCCESS(aws_mqtt5_to_mqtt3_adapter_test_fixture_init(&fixture, allocator, &test_fixture_options));
4428+
4429+
struct aws_mqtt_client_connection *connection = fixture.connection;
4430+
4431+
struct aws_mqtt_iot_sdk_metrics metrics = {
4432+
.library_name = aws_byte_cursor_from_c_str("TestSDK/1.0"),
4433+
.metadata_entries = NULL,
4434+
.metadata_count = 0,
4435+
};
4436+
4437+
ASSERT_SUCCESS(aws_mqtt_client_connection_set_metrics(connection, &metrics));
4438+
4439+
aws_mqtt5_to_mqtt3_adapter_test_fixture_clean_up(&fixture);
4440+
aws_mqtt_library_clean_up();
4441+
4442+
return AWS_OP_SUCCESS;
4443+
}
4444+
4445+
AWS_TEST_CASE(mqtt5to3_adapter_set_metrics_valid, s_mqtt5to3_adapter_connection_set_metrics_valid_fn)
4446+
4447+
/**
4448+
* Test that aws_mqtt_client_connection_set_metrics works correctly with NULL metrics (disables metrics)
4449+
*/
4450+
static int s_mqtt5to3_adapter_connection_set_metrics_null_fn(struct aws_allocator *allocator, void *ctx) {
4451+
(void)ctx;
4452+
4453+
aws_mqtt_library_init(allocator);
4454+
4455+
struct mqtt5_client_test_options test_options;
4456+
aws_mqtt5_client_test_init_default_options(&test_options);
4457+
4458+
struct aws_mqtt5_client_mqtt5_mock_test_fixture_options test_fixture_options = {
4459+
.client_options = &test_options.client_options,
4460+
.server_function_table = &test_options.server_function_table,
4461+
};
4462+
4463+
struct aws_mqtt5_to_mqtt3_adapter_test_fixture fixture;
4464+
ASSERT_SUCCESS(aws_mqtt5_to_mqtt3_adapter_test_fixture_init(&fixture, allocator, &test_fixture_options));
4465+
4466+
struct aws_mqtt_client_connection *connection = fixture.connection;
4467+
4468+
ASSERT_SUCCESS(aws_mqtt_client_connection_set_metrics(connection, NULL));
4469+
4470+
aws_mqtt5_to_mqtt3_adapter_test_fixture_clean_up(&fixture);
4471+
aws_mqtt_library_clean_up();
4472+
4473+
return AWS_OP_SUCCESS;
4474+
}
4475+
4476+
AWS_TEST_CASE(mqtt5to3_adapter_set_metrics_null, s_mqtt5to3_adapter_connection_set_metrics_null_fn)
4477+
4478+
/**
4479+
* Test that aws_mqtt_client_connection_set_metrics rejects invalid UTF-8 in library name
4480+
*/
4481+
static int s_mqtt5to3_adapter_connection_set_metrics_invalid_utf8_library_fn(
4482+
struct aws_allocator *allocator,
4483+
void *ctx) {
4484+
(void)ctx;
4485+
4486+
aws_mqtt_library_init(allocator);
4487+
4488+
struct mqtt5_client_test_options test_options;
4489+
aws_mqtt5_client_test_init_default_options(&test_options);
4490+
4491+
struct aws_mqtt5_client_mqtt5_mock_test_fixture_options test_fixture_options = {
4492+
.client_options = &test_options.client_options,
4493+
.server_function_table = &test_options.server_function_table,
4494+
};
4495+
4496+
struct aws_mqtt5_to_mqtt3_adapter_test_fixture fixture;
4497+
ASSERT_SUCCESS(aws_mqtt5_to_mqtt3_adapter_test_fixture_init(&fixture, allocator, &test_fixture_options));
4498+
4499+
struct aws_mqtt_client_connection *connection = fixture.connection;
4500+
4501+
/* Invalid UTF-8 sequence */
4502+
struct aws_byte_cursor invalid_utf8_library = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("TestSDK\xFF\xFE");
4503+
4504+
struct aws_mqtt_iot_sdk_metrics metrics = {
4505+
.library_name = invalid_utf8_library,
4506+
.metadata_entries = NULL,
4507+
.metadata_count = 0,
4508+
};
4509+
4510+
ASSERT_FAILS(aws_mqtt_client_connection_set_metrics(connection, &metrics));
4511+
ASSERT_INT_EQUALS(aws_last_error(), AWS_ERROR_INVALID_UTF8);
4512+
4513+
aws_mqtt5_to_mqtt3_adapter_test_fixture_clean_up(&fixture);
4514+
aws_mqtt_library_clean_up();
4515+
4516+
return AWS_OP_SUCCESS;
4517+
}
4518+
4519+
AWS_TEST_CASE(
4520+
mqtt5to3_adapter_set_metrics_invalid_utf8_library,
4521+
s_mqtt5to3_adapter_connection_set_metrics_invalid_utf8_library_fn)

0 commit comments

Comments
 (0)