Skip to content

Commit 3af94a9

Browse files
committed
Merge branch 'metrics_mqtt3' of github.com:awslabs/aws-c-mqtt into metrics_mqtt5
2 parents 81f1bc1 + e957a64 commit 3af94a9

5 files changed

Lines changed: 140 additions & 151 deletions

File tree

include/aws/mqtt/private/client_impl_shared.h

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ AWS_MQTT_API struct aws_event_loop *aws_mqtt_client_connection_get_event_loop(
175175
* @param metrics The metrics configuration
176176
* @param output_username Buffer to store the modified username. If the function succeed, caller is responsible to
177177
* release the memory for output_username.
178+
* @param out_full_username_size If not NULL, will be set to the full size of the username with metrics appended
178179
*
179180
* @return AWS_OP_SUCCESS on success, AWS_OP_ERR on failure
180181
*/
@@ -183,15 +184,8 @@ int aws_mqtt_append_sdk_metrics_to_username(
183184
struct aws_allocator *allocator,
184185
const struct aws_byte_cursor *original_username,
185186
const struct aws_mqtt_iot_sdk_metrics metrics,
186-
struct aws_byte_buf *output_username);
187-
188-
/**
189-
* Get final username length
190-
*/
191-
AWS_MQTT_API
192-
size_t aws_mqtt_append_sdk_metrics_to_username_size(
193-
const struct aws_byte_cursor *original_username,
194-
const struct aws_mqtt_iot_sdk_metrics metrics);
187+
struct aws_byte_buf *output_username,
188+
size_t *out_full_username_size);
195189

196190
/**
197191
* Validates that all string fields in aws_mqtt_iot_sdk_metrics are valid UTF-8

source/client.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -640,7 +640,8 @@ static void s_mqtt_client_init(
640640
connection->allocator,
641641
&username_cur,
642642
connection->metrics->storage_view,
643-
&connection->username_with_metrics_buf) == AWS_OP_SUCCESS) {
643+
&connection->username_with_metrics_buf,
644+
NULL) == AWS_OP_SUCCESS) {
644645
username_cur = aws_byte_cursor_from_buf(&connection->username_with_metrics_buf);
645646
} else {
646647
AWS_LOGF_WARN(

source/client_impl_shared.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ int aws_mqtt_iot_sdk_metrics_storage_init(
272272

273273
struct aws_mqtt_iot_sdk_metrics *storage_view = &metrics_storage->storage_view;
274274

275-
// TODO: add metadata entries when enabled
275+
// TODO Future Work: add metadata entries once we implemented the metadata feature
276276
//
277277
// if (aws_array_list_init_dynamic(
278278
// &metrics_storage->metadata_entries,
@@ -312,9 +312,11 @@ int aws_mqtt_iot_sdk_metrics_storage_init(
312312
return AWS_OP_SUCCESS;
313313

314314
metrics_storage_error:
315-
if (aws_array_list_is_valid(&metrics_storage->metadata_entries)) {
316-
aws_array_list_clean_up(&metrics_storage->metadata_entries);
317-
}
315+
// TODO Future Work: add metadata entries once we implemented the metadata feature
316+
// if (aws_array_list_is_valid(&metrics_storage->metadata_entries)) {
317+
// aws_array_list_clean_up(&metrics_storage->metadata_entries);
318+
// }
319+
318320
aws_byte_buf_clean_up(&metrics_storage->storage);
319321

320322
return AWS_OP_ERR;

source/mqtt_iot_sdk_metrics.c

Lines changed: 116 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,78 @@
44
*/
55

66
#include <aws/common/byte_buf.h>
7-
#include <aws/common/encoding.h>
8-
#include <aws/common/string.h>
97
#include <aws/common/system_info.h>
8+
#include <aws/common/uri.h>
109
#include <aws/mqtt/mqtt.h>
1110
#include <aws/mqtt/private/client_impl_shared.h>
1211

1312
#include <stdio.h>
1413

15-
// Maximum MQTT5 Content Type size https://docs.aws.amazon.com/general/latest/gr/iot-core.html#thing-limits
16-
const int AWS_IOT_MAX_CONTENT_SIZE = 256;
14+
// MQTT payload size https://docs.aws.amazon.com/general/latest/gr/iot-core.html#thing-limits
15+
const int AWS_IOT_MAX_CONTENT_SIZE = 128 * 1024;
16+
const size_t DEFAULT_QUERY_PARAM_COUNT = 10;
17+
18+
// Build username query string from params_list, the caller is responsible to init and clean up output_username
19+
// If output_username is NULL, the function will just calculate the full username size and return it in
20+
// out_full_username_size
21+
int s_build_username_query(
22+
const struct aws_byte_cursor *base_username,
23+
size_t base_username_length,
24+
const struct aws_array_list *params_list,
25+
struct aws_byte_buf *output_username,
26+
size_t *out_full_username_size) {
27+
28+
if (output_username) {
29+
aws_byte_buf_write(output_username, base_username->ptr, base_username_length);
30+
}
31+
32+
if (out_full_username_size) {
33+
*out_full_username_size = base_username_length;
34+
}
35+
36+
struct aws_byte_cursor query_delim = aws_byte_cursor_from_c_str("?");
37+
struct aws_byte_cursor query_param_amp = aws_byte_cursor_from_c_str("&");
38+
struct aws_byte_cursor key_value_delim = aws_byte_cursor_from_c_str("=");
39+
40+
size_t params_count = aws_array_list_length(params_list);
41+
for (size_t i = 0; i < params_count; ++i) {
42+
struct aws_uri_param param;
43+
AWS_ZERO_STRUCT(param);
44+
aws_array_list_get_at(params_list, &param, i);
45+
46+
if (i == 0 && output_username) {
47+
aws_byte_buf_append(output_username, &query_delim);
48+
} else if (i > 0 && output_username) {
49+
aws_byte_buf_append(output_username, &query_param_amp);
50+
}
51+
52+
if (out_full_username_size) {
53+
*out_full_username_size += 1;
54+
}
55+
56+
if (output_username) {
57+
aws_byte_buf_append(output_username, &param.key);
58+
aws_byte_buf_append(output_username, &key_value_delim);
59+
aws_byte_buf_append(output_username, &param.value);
60+
}
61+
62+
if (out_full_username_size) {
63+
*out_full_username_size += param.key.len + 1 + param.value.len;
64+
}
65+
}
66+
67+
return AWS_OP_SUCCESS;
68+
}
1769

70+
// TODO Future Work: we ignored the metadata field for now, will add them in future support
1871
int aws_mqtt_append_sdk_metrics_to_username(
1972
struct aws_allocator *allocator,
2073
const struct aws_byte_cursor *original_username,
2174
const struct aws_mqtt_iot_sdk_metrics metrics,
22-
struct aws_byte_buf *output_username) {
75+
struct aws_byte_buf *output_username,
76+
size_t *out_full_username_size) {
2377

24-
if (!allocator || !output_username) {
78+
if (!allocator) {
2579
return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
2680
}
2781

@@ -35,153 +89,85 @@ int aws_mqtt_append_sdk_metrics_to_username(
3589
return AWS_OP_ERR;
3690
}
3791

38-
/* Check if the attributes already exists in username */
39-
bool has_sdk = false;
40-
bool has_platform = false;
41-
bool has_query = false;
42-
43-
struct aws_byte_cursor sdk_str = aws_byte_cursor_from_c_str("SDK=");
44-
struct aws_byte_cursor platform_str = aws_byte_cursor_from_c_str("Platform=");
92+
int result = AWS_OP_ERR;
93+
// The length of the base username part not including query parameters
94+
size_t base_username_length = 0;
4595
struct aws_byte_cursor question_mark_str = aws_byte_cursor_from_c_str("?");
46-
struct aws_byte_cursor amp = aws_byte_cursor_from_c_str("&");
96+
struct aws_byte_cursor sdk_str = aws_byte_cursor_from_c_str("SDK");
97+
struct aws_byte_cursor platform_str = aws_byte_cursor_from_c_str("Platform");
4798

48-
// TODO: we ignored the metadata field for now, need to add them later
99+
struct aws_array_list params_list;
100+
aws_array_list_init_dynamic(&params_list, allocator, DEFAULT_QUERY_PARAM_COUNT, sizeof(struct aws_uri_param));
49101

50102
if (original_username && original_username->len > 0) {
51103
struct aws_byte_cursor question_mark_find;
52-
has_query =
53-
AWS_OP_SUCCESS == aws_byte_cursor_find_exact(original_username, &question_mark_str, &question_mark_find);
54-
if (has_query) {
55-
struct aws_byte_cursor temp_cursor;
56-
has_sdk = AWS_OP_SUCCESS == aws_byte_cursor_find_exact(&question_mark_find, &sdk_str, &temp_cursor);
57-
has_platform =
58-
AWS_OP_SUCCESS == aws_byte_cursor_find_exact(&question_mark_find, &platform_str, &temp_cursor);
59-
}
60-
}
61104

62-
/* Add SDK if not present */
63-
if (!has_sdk) {
64-
if (aws_byte_buf_append(&metrics_string, &sdk_str)) {
65-
goto error;
66-
}
67-
68-
struct aws_byte_cursor sdk_attr_value =
69-
metrics.library_name.len > 0 ? metrics.library_name : aws_byte_cursor_from_c_str("IoTDeviceSDK/C");
70-
if (aws_byte_buf_append(&metrics_string, &sdk_attr_value)) {
71-
goto error;
105+
if (AWS_OP_SUCCESS == aws_byte_cursor_find_exact(original_username, &question_mark_str, &question_mark_find)) {
106+
base_username_length = question_mark_find.ptr - original_username->ptr;
107+
// Advance cursor to skip the "?" character
108+
aws_byte_cursor_advance(&question_mark_find, 1);
109+
aws_byte_buf_append(&metrics_string, &question_mark_find);
110+
aws_query_string_params(question_mark_find, &params_list);
111+
} else {
112+
base_username_length = original_username->len;
72113
}
73114
}
74115

75-
/* Add Platform if not present */
76-
if (!has_platform) {
77-
struct aws_byte_cursor platform_cursor = aws_get_platform_build_os_string();
78-
if (platform_cursor.len > 0) {
79-
if (metrics_string.len > 0) {
80-
if (aws_byte_buf_append(&metrics_string, &amp)) {
81-
goto error;
82-
}
83-
}
84-
85-
if (aws_byte_buf_append(&metrics_string, &platform_str) ||
86-
aws_byte_buf_append(&metrics_string, &platform_cursor)) {
87-
goto error;
88-
}
116+
bool found_sdk = false;
117+
bool found_platform = false;
118+
119+
size_t params_count = aws_array_list_length(&params_list);
120+
for (size_t i = 0; i < params_count; ++i) {
121+
struct aws_uri_param param;
122+
AWS_ZERO_STRUCT(param);
123+
aws_array_list_get_at(&params_list, &param, i);
124+
if (aws_byte_cursor_eq(&param.key, &sdk_str)) {
125+
found_sdk = true;
126+
} else if (aws_byte_cursor_eq(&param.key, &platform_str)) {
127+
found_platform = true;
89128
}
90129
}
91130

92-
/* Build final output */
93-
// TODO: we should consider the case where total size extceeds MQTT username limit
94-
size_t total_size = (original_username ? original_username->len : 0) + metrics_string.len + 1;
95-
96-
if (aws_byte_buf_init(output_username, allocator, total_size)) {
97-
goto error;
131+
if (!found_sdk) {
132+
struct aws_uri_param sdk_params = {
133+
.key = sdk_str,
134+
.value = metrics.library_name.len > 0 ? metrics.library_name : aws_byte_cursor_from_c_str("IoTDeviceSDK/C"),
135+
};
136+
aws_array_list_push_back(&params_list, &sdk_params);
98137
}
99138

100-
/* Add original username */
101-
if (original_username && original_username->len > 0) {
102-
if (aws_byte_buf_append(output_username, original_username)) {
103-
goto error_output;
104-
}
139+
if (!found_platform) {
140+
struct aws_uri_param platform_params = {
141+
.key = platform_str,
142+
.value = aws_get_platform_build_os_string(),
143+
};
144+
aws_array_list_push_back(&params_list, &platform_params);
105145
}
106146

107-
/* Add metrics with separator */
108-
if (metrics_string.len > 0) {
109-
110-
struct aws_byte_cursor metrics_cursor = aws_byte_cursor_from_buf(&metrics_string);
147+
// Rebuild metrics string from params_list
148+
// First path to calculate total size
149+
size_t total_size = 0;
150+
s_build_username_query(original_username, base_username_length, &params_list, NULL, &total_size);
111151

112-
struct aws_byte_cursor separator = has_query ? amp : question_mark_str;
113-
if (aws_byte_buf_append(output_username, &separator)) {
114-
goto error_output;
115-
}
116-
117-
if (aws_byte_buf_append(output_username, &metrics_cursor)) {
118-
goto error_output;
119-
}
152+
if (output_username && aws_byte_buf_init(output_username, allocator, total_size)) {
153+
goto cleanup;
120154
}
121155

122-
aws_byte_buf_clean_up(&metrics_string);
123-
return AWS_OP_SUCCESS;
156+
// build final output username
157+
s_build_username_query(
158+
original_username, base_username_length, &params_list, output_username, out_full_username_size);
124159

125-
error_output:
126-
aws_byte_buf_clean_up(output_username);
127-
error:
128160
aws_byte_buf_clean_up(&metrics_string);
129-
return AWS_OP_ERR;
130-
}
131-
132-
size_t aws_mqtt_append_sdk_metrics_to_username_size(
133-
const struct aws_byte_cursor *original_username,
134-
const struct aws_mqtt_iot_sdk_metrics metrics) {
135-
136-
/* Build metrics string */
137-
size_t metrics_string_size = 0;
138-
139-
/* Check if the attributes already exists in username */
140-
bool has_sdk = false;
141-
bool has_platform = false;
142-
bool has_query = false;
143-
144-
struct aws_byte_cursor sdk_str = aws_byte_cursor_from_c_str("SDK=");
145-
struct aws_byte_cursor platform_str = aws_byte_cursor_from_c_str("Platform=");
146-
struct aws_byte_cursor question_mark_str = aws_byte_cursor_from_c_str("?");
161+
result = AWS_OP_SUCCESS;
147162

148-
// TODO: we ignored the metadata field for now, need to add them in the future
149-
150-
if (original_username && original_username->len > 0) {
151-
struct aws_byte_cursor question_mark_find;
152-
has_query =
153-
AWS_OP_SUCCESS == aws_byte_cursor_find_exact(original_username, &question_mark_str, &question_mark_find);
154-
if (has_query) {
155-
struct aws_byte_cursor temp_cursor;
156-
has_sdk = AWS_OP_SUCCESS == aws_byte_cursor_find_exact(&question_mark_find, &sdk_str, &temp_cursor);
157-
has_platform =
158-
AWS_OP_SUCCESS == aws_byte_cursor_find_exact(&question_mark_find, &platform_str, &temp_cursor);
159-
}
160-
}
161-
162-
/* Add SDK if not present */
163-
if (!has_sdk) {
164-
metrics_string_size += sdk_str.len;
165-
166-
struct aws_byte_cursor sdk_attr_value =
167-
metrics.library_name.len > 0 ? metrics.library_name : aws_byte_cursor_from_c_str("IoTDeviceSDK/C");
168-
169-
metrics_string_size += sdk_attr_value.len;
163+
cleanup:
164+
if (aws_array_list_is_valid(&params_list)) {
165+
aws_array_list_clean_up(&params_list);
170166
}
171167

172-
/* Add Platform if not present */
173-
if (!has_platform) {
174-
struct aws_byte_cursor platform_cursor = aws_get_platform_build_os_string();
175-
if (platform_cursor.len > 0) {
176-
// Add amp sign if metrics is not empty
177-
metrics_string_size += metrics_string_size + metrics_string_size > 0 ? 1 : 0;
178-
179-
metrics_string_size += platform_str.len + platform_cursor.len;
180-
}
168+
if (result == AWS_OP_ERR && aws_byte_buf_is_valid(output_username)) {
169+
aws_byte_buf_clean_up(output_username);
181170
}
182-
183-
/* Build final output */
184-
/* original_username + 1 character of "?" or "&" + metrics string*/
185-
size_t total_size = (original_username ? original_username->len : 0) + 1 + metrics_string_size;
186-
return total_size;
171+
aws_byte_buf_clean_up(&metrics_string);
172+
return result;
187173
}

0 commit comments

Comments
 (0)