Skip to content

Commit

Permalink
Best effort translation from mqtt5 to mqtt3 error codes
Browse files Browse the repository at this point in the history
  • Loading branch information
bretambrose committed Jul 14, 2023
1 parent 561ef61 commit d9b03ec
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 44 deletions.
98 changes: 94 additions & 4 deletions source/v5/mqtt3_to_mqtt5_adapter.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,46 @@
#include <aws/mqtt/private/v5/mqtt5_client_impl.h>
#include <aws/mqtt/v5/mqtt5_listener.h>

/*
* A best-effort-but-not-100%-accurate translation from mqtt5 error codes to mqtt311 error codes.
*/
static int s_translate_mqtt5_error_code_to_mqtt311(int error_code) {
switch (error_code) {
case AWS_ERROR_MQTT5_ENCODE_FAILURE:
case AWS_ERROR_MQTT5_DECODE_PROTOCOL_ERROR:
return AWS_ERROR_MQTT_PROTOCOL_ERROR;

case AWS_ERROR_MQTT5_CONNACK_CONNECTION_REFUSED:
return AWS_ERROR_MQTT_PROTOCOL_ERROR; /* a decidedly strange choice by the 311 implementation */

case AWS_ERROR_MQTT5_CONNACK_TIMEOUT:
case AWS_ERROR_MQTT5_PING_RESPONSE_TIMEOUT:
return AWS_ERROR_MQTT_TIMEOUT;

case AWS_ERROR_MQTT5_USER_REQUESTED_STOP:
case AWS_ERROR_MQTT5_CLIENT_TERMINATED:
return AWS_IO_SOCKET_CLOSED;

case AWS_ERROR_MQTT5_DISCONNECT_RECEIVED:
return AWS_ERROR_MQTT_UNEXPECTED_HANGUP;

case AWS_ERROR_MQTT5_OPERATION_FAILED_DUE_TO_OFFLINE_QUEUE_POLICY:
return AWS_ERROR_MQTT_CANCELLED_FOR_CLEAN_SESSION;

case AWS_ERROR_MQTT5_ENCODE_SIZE_UNSUPPORTED_PACKET_TYPE:
return AWS_ERROR_MQTT_INVALID_PACKET_TYPE;

case AWS_ERROR_MQTT5_OPERATION_PROCESSING_FAILURE:
return AWS_ERROR_MQTT_PROTOCOL_ERROR;

case AWS_ERROR_MQTT5_INVALID_UTF8_STRING:
return AWS_ERROR_MQTT_INVALID_TOPIC;

default:
return error_code;
}
}

struct aws_mqtt_adapter_final_destroy_task {
struct aws_task task;
struct aws_allocator *allocator;
Expand Down Expand Up @@ -389,15 +429,21 @@ static int s_aws_mqtt3_to_mqtt5_adapter_safe_lifecycle_handler(
*/
if (event->error_code != AWS_ERROR_MQTT_CONNECTION_RESET_FOR_ADAPTER_CONNECT) {
if (adapter->adapter_state != AWS_MQTT_AS_STAY_DISCONNECTED) {
int mqtt311_error_code = s_translate_mqtt5_error_code_to_mqtt311(event->error_code);

if (adapter->on_connection_failure != NULL) {
(*adapter->on_connection_failure)(
&adapter->base, event->error_code, adapter->on_connection_failure_user_data);
&adapter->base, mqtt311_error_code, adapter->on_connection_failure_user_data);
}

if (adapter->adapter_state == AWS_MQTT_AS_FIRST_CONNECT) {
if (adapter->on_connection_complete != NULL) {
(*adapter->on_connection_complete)(
&adapter->base, event->error_code, 0, false, adapter->on_connection_complete_user_data);
&adapter->base,
mqtt311_error_code,
0,
false,
adapter->on_connection_complete_user_data);

adapter->on_connection_complete = NULL;
adapter->on_connection_complete_user_data = NULL;
Expand All @@ -418,7 +464,10 @@ static int s_aws_mqtt3_to_mqtt5_adapter_safe_lifecycle_handler(
if (adapter->on_interrupted != NULL && adapter->adapter_state == AWS_MQTT_AS_STAY_CONNECTED &&
event->error_code != AWS_ERROR_MQTT_CONNECTION_RESET_FOR_ADAPTER_CONNECT) {

(*adapter->on_interrupted)(&adapter->base, event->error_code, adapter->on_interrupted_user_data);
(*adapter->on_interrupted)(
&adapter->base,
s_translate_mqtt5_error_code_to_mqtt311(event->error_code),
adapter->on_interrupted_user_data);
}
break;

Expand Down Expand Up @@ -1136,7 +1185,9 @@ static void s_aws_mqtt5_adapter_websocket_handshake_completion_fn(
struct aws_mqtt_client_connection_5_impl *adapter = complete_ctx;

(*adapter->mqtt5_websocket_handshake_completion_function)(
request, error_code, adapter->mqtt5_websocket_handshake_completion_user_data);
request,
s_translate_mqtt5_error_code_to_mqtt311(error_code),
adapter->mqtt5_websocket_handshake_completion_user_data);

aws_ref_count_release(&adapter->internal_refs);
}
Expand Down Expand Up @@ -1414,6 +1465,16 @@ static int s_aws_mqtt_client_connection_5_set_will(

struct aws_mqtt_client_connection_5_impl *adapter = impl;

/* check qos */
if (qos < 0 || qos > AWS_MQTT_QOS_EXACTLY_ONCE) {
return aws_raise_error(AWS_ERROR_MQTT_INVALID_QOS);
}

/* check topic */
if (!aws_mqtt_is_valid_topic(topic)) {
return aws_raise_error(AWS_ERROR_MQTT_INVALID_TOPIC);
}

struct aws_mqtt_set_will_task *task =
s_aws_mqtt_set_will_task_new(adapter->allocator, adapter, topic, qos, retain, payload);
if (task == NULL) {
Expand Down Expand Up @@ -1752,6 +1813,11 @@ static uint16_t s_aws_mqtt_client_connection_5_publish(
aws_mqtt_op_complete_fn *on_complete,
void *userdata) {

/* check qos */
if (qos < 0 || qos > AWS_MQTT_QOS_EXACTLY_ONCE) {
return aws_raise_error(AWS_ERROR_MQTT_INVALID_QOS);
}

if (!aws_mqtt_is_valid_topic(topic)) {
aws_raise_error(AWS_ERROR_MQTT_INVALID_TOPIC);
return 0;
Expand Down Expand Up @@ -1944,6 +2010,26 @@ static void s_aws_mqtt3_to_mqtt5_adapter_subscribe_completion_fn(
&subscribe_op->base.adapter->operational_state, subscribe_op->base.id);
}

static int s_validate_adapter_subscribe_options(
size_t subscription_count,
struct aws_mqtt_topic_subscription *subscriptions) {
for (size_t i = 0; i < subscription_count; ++i) {
struct aws_mqtt_topic_subscription *subscription = subscriptions + i;

/* check qos */
if (subscription->qos < 0 || subscription->qos > AWS_MQTT_QOS_EXACTLY_ONCE) {
return aws_raise_error(AWS_ERROR_MQTT_INVALID_QOS);
}

/* check topic */
if (!aws_mqtt_is_valid_topic_filter(&subscription->topic)) {
return aws_raise_error(AWS_ERROR_MQTT_INVALID_TOPIC);
}
}

return AWS_OP_SUCCESS;
}

static int s_aws_mqtt3_to_mqtt5_adapter_build_subscribe(
struct aws_mqtt3_to_mqtt5_adapter_operation_subscribe *subscribe_op,
size_t subscription_count,
Expand Down Expand Up @@ -2008,6 +2094,10 @@ struct aws_mqtt3_to_mqtt5_adapter_operation_subscribe *aws_mqtt3_to_mqtt5_adapte
struct aws_allocator *allocator,
const struct aws_mqtt3_to_mqtt5_adapter_subscribe_options *options) {

if (s_validate_adapter_subscribe_options(options->subscription_count, options->subscriptions)) {
return NULL;
}

struct aws_mqtt3_to_mqtt5_adapter_operation_subscribe *subscribe_op =
aws_mem_calloc(allocator, 1, sizeof(struct aws_mqtt3_to_mqtt5_adapter_operation_subscribe));

Expand Down
83 changes: 43 additions & 40 deletions tests/v5/mqtt3_to_mqtt5_adapter_tests.c
Original file line number Diff line number Diff line change
Expand Up @@ -1192,7 +1192,7 @@ static int s_verify_bad_connectivity_callbacks(struct aws_mqtt3_to_mqtt5_adapter
},
{
.type = AWS_MQTT3_LET_INTERRUPTED,
.error_code = AWS_ERROR_MQTT5_DISCONNECT_RECEIVED,
.error_code = AWS_ERROR_MQTT_UNEXPECTED_HANGUP,
},
{
.type = AWS_MQTT3_LET_CONNECTION_SUCCESS,
Expand All @@ -1202,7 +1202,7 @@ static int s_verify_bad_connectivity_callbacks(struct aws_mqtt3_to_mqtt5_adapter
},
{
.type = AWS_MQTT3_LET_INTERRUPTED,
.error_code = AWS_ERROR_MQTT5_DISCONNECT_RECEIVED,
.error_code = AWS_ERROR_MQTT_UNEXPECTED_HANGUP,
},
{
.type = AWS_MQTT3_LET_CONNECTION_SUCCESS,
Expand All @@ -1212,7 +1212,7 @@ static int s_verify_bad_connectivity_callbacks(struct aws_mqtt3_to_mqtt5_adapter
},
{
.type = AWS_MQTT3_LET_INTERRUPTED,
.error_code = AWS_ERROR_MQTT5_DISCONNECT_RECEIVED,
.error_code = AWS_ERROR_MQTT_UNEXPECTED_HANGUP,
},
};
ASSERT_SUCCESS(s_aws_mqtt3_to_mqtt5_adapter_test_fixture_verify_lifecycle_sequence_starts_with(
Expand Down Expand Up @@ -1413,11 +1413,11 @@ static int s_mqtt3to5_adapter_connect_failure_connect_success_via_mqtt5_fn(struc
struct aws_mqtt3_lifecycle_event expected_events[] = {
{
.type = AWS_MQTT3_LET_CONNECTION_FAILURE,
.error_code = AWS_ERROR_MQTT5_CONNACK_CONNECTION_REFUSED,
.error_code = AWS_ERROR_MQTT_PROTOCOL_ERROR,
},
{
.type = AWS_MQTT3_LET_CONNECTION_COMPLETE,
.error_code = AWS_ERROR_MQTT5_CONNACK_CONNECTION_REFUSED,
.error_code = AWS_ERROR_MQTT_PROTOCOL_ERROR,
},
};
ASSERT_SUCCESS(s_aws_mqtt3_to_mqtt5_adapter_test_fixture_verify_lifecycle_sequence(
Expand All @@ -1437,11 +1437,11 @@ static int s_mqtt3to5_adapter_connect_failure_connect_success_via_mqtt5_fn(struc
struct aws_mqtt3_lifecycle_event expected_reconnect_events[] = {
{
.type = AWS_MQTT3_LET_CONNECTION_FAILURE,
.error_code = AWS_ERROR_MQTT5_CONNACK_CONNECTION_REFUSED,
.error_code = AWS_ERROR_MQTT_PROTOCOL_ERROR,
},
{
.type = AWS_MQTT3_LET_CONNECTION_COMPLETE,
.error_code = AWS_ERROR_MQTT5_CONNACK_CONNECTION_REFUSED,
.error_code = AWS_ERROR_MQTT_PROTOCOL_ERROR,
},
{
.type = AWS_MQTT3_LET_CONNECTION_SUCCESS,
Expand Down Expand Up @@ -1646,19 +1646,19 @@ static int s_mqtt3to5_adapter_connect_reconnect_failures_fn(struct aws_allocator
},
{
.type = AWS_MQTT3_LET_INTERRUPTED,
.error_code = AWS_ERROR_MQTT5_DISCONNECT_RECEIVED,
.error_code = AWS_ERROR_MQTT_UNEXPECTED_HANGUP,
},
{
.type = AWS_MQTT3_LET_CONNECTION_FAILURE,
.error_code = AWS_ERROR_MQTT5_CONNACK_CONNECTION_REFUSED,
.error_code = AWS_ERROR_MQTT_PROTOCOL_ERROR,
},
{
.type = AWS_MQTT3_LET_CONNECTION_FAILURE,
.error_code = AWS_ERROR_MQTT5_CONNACK_CONNECTION_REFUSED,
.error_code = AWS_ERROR_MQTT_PROTOCOL_ERROR,
},
{
.type = AWS_MQTT3_LET_CONNECTION_FAILURE,
.error_code = AWS_ERROR_MQTT5_CONNACK_CONNECTION_REFUSED,
.error_code = AWS_ERROR_MQTT_PROTOCOL_ERROR,
},
};
ASSERT_SUCCESS(s_aws_mqtt3_to_mqtt5_adapter_test_fixture_verify_lifecycle_sequence_starts_with(
Expand Down Expand Up @@ -3222,35 +3222,38 @@ static int s_mqtt3to5_adapter_subscribe_multi_overlapping_publish_fn(struct aws_
struct aws_byte_cursor topic2 = aws_byte_cursor_from_c_str("hello/+");
struct aws_byte_cursor topic3 = aws_byte_cursor_from_c_str("derp");

aws_mqtt_client_connection_subscribe(
connection,
&topic1,
AWS_MQTT_QOS_AT_LEAST_ONCE,
s_aws_mqtt3_to_mqtt5_adapter_test_fixture_record_topic_specific_publish,
&fixture,
NULL,
s_aws_mqtt3_to_mqtt5_adapter_test_fixture_record_subscribe_complete,
&fixture);

aws_mqtt_client_connection_subscribe(
connection,
&topic2,
AWS_MQTT_QOS_AT_MOST_ONCE,
s_aws_mqtt3_to_mqtt5_adapter_test_fixture_record_topic_specific_publish,
&fixture,
NULL,
s_aws_mqtt3_to_mqtt5_adapter_test_fixture_record_subscribe_complete,
&fixture);

aws_mqtt_client_connection_subscribe(
connection,
&topic3,
AWS_MQTT_QOS_AT_LEAST_ONCE,
s_aws_mqtt3_to_mqtt5_adapter_test_fixture_record_topic_specific_publish,
&fixture,
NULL,
s_aws_mqtt3_to_mqtt5_adapter_test_fixture_record_subscribe_complete,
&fixture);
ASSERT_TRUE(
0 != aws_mqtt_client_connection_subscribe(
connection,
&topic1,
AWS_MQTT_QOS_AT_LEAST_ONCE,
s_aws_mqtt3_to_mqtt5_adapter_test_fixture_record_topic_specific_publish,
&fixture,
NULL,
s_aws_mqtt3_to_mqtt5_adapter_test_fixture_record_subscribe_complete,
&fixture));

ASSERT_TRUE(
0 != aws_mqtt_client_connection_subscribe(
connection,
&topic2,
AWS_MQTT_QOS_AT_MOST_ONCE,
s_aws_mqtt3_to_mqtt5_adapter_test_fixture_record_topic_specific_publish,
&fixture,
NULL,
s_aws_mqtt3_to_mqtt5_adapter_test_fixture_record_subscribe_complete,
&fixture));

ASSERT_TRUE(
0 != aws_mqtt_client_connection_subscribe(
connection,
&topic3,
AWS_MQTT_QOS_AT_LEAST_ONCE,
s_aws_mqtt3_to_mqtt5_adapter_test_fixture_record_topic_specific_publish,
&fixture,
NULL,
s_aws_mqtt3_to_mqtt5_adapter_test_fixture_record_subscribe_complete,
&fixture));

s_wait_for_n_adapter_operation_events(&fixture, AWS_MQTT3_OET_SUBSCRIBE_COMPLETE, 3);

Expand Down

0 comments on commit d9b03ec

Please sign in to comment.