Skip to content

Commit f0cc34c

Browse files
authored
Fix handling of websocket failed transform for MQTT311 connection (#383)
1 parent 1bf1224 commit f0cc34c

File tree

3 files changed

+80
-3
lines changed

3 files changed

+80
-3
lines changed

source/client.c

+36-3
Original file line numberDiff line numberDiff line change
@@ -1363,6 +1363,27 @@ static int s_websocket_connect(struct aws_mqtt_client_connection_311_impl *conne
13631363
return AWS_OP_ERR;
13641364
}
13651365

1366+
struct mqtt_on_websocket_setup_task_arg {
1367+
struct aws_allocator *allocator;
1368+
struct aws_task task;
1369+
struct aws_mqtt_client_connection_311_impl *connection;
1370+
int error_code;
1371+
};
1372+
1373+
static void s_on_websocket_setup_task_fn(struct aws_task *task, void *userdata, enum aws_task_status status) {
1374+
(void)task;
1375+
(void)status;
1376+
1377+
struct mqtt_on_websocket_setup_task_arg *on_websocket_setup_task_arg = userdata;
1378+
struct aws_mqtt_client_connection_311_impl *connection = on_websocket_setup_task_arg->connection;
1379+
int error_code = on_websocket_setup_task_arg->error_code;
1380+
1381+
aws_mem_release(on_websocket_setup_task_arg->allocator, on_websocket_setup_task_arg);
1382+
1383+
struct aws_websocket_on_connection_setup_data websocket_setup = {.error_code = error_code};
1384+
s_on_websocket_setup(&websocket_setup, connection);
1385+
}
1386+
13661387
static void s_websocket_handshake_transform_complete(
13671388
struct aws_http_message *handshake_request,
13681389
int error_code,
@@ -1417,9 +1438,21 @@ static void s_websocket_handshake_transform_complete(
14171438
return;
14181439

14191440
error:;
1420-
/* Proceed to next step, telling it that we failed. */
1421-
struct aws_websocket_on_connection_setup_data websocket_setup = {.error_code = error_code};
1422-
s_on_websocket_setup(&websocket_setup, connection);
1441+
/* Proceed to next step, telling it that we failed.
1442+
* s_on_websocket_setup will shutdown MQTT connection, and this MUST happen on the MQTT connection's event loop. */
1443+
struct mqtt_on_websocket_setup_task_arg *on_websocket_setup_task_arg =
1444+
aws_mem_calloc(connection->allocator, 1, sizeof(struct mqtt_on_websocket_setup_task_arg));
1445+
on_websocket_setup_task_arg->allocator = connection->allocator;
1446+
/* NOTE: No need in acquiring MQTT connection ref counter, as it is already acquired at the start of connection
1447+
* process. s_on_websocket_setup will release it. */
1448+
on_websocket_setup_task_arg->connection = connection;
1449+
on_websocket_setup_task_arg->error_code = error_code;
1450+
aws_task_init(
1451+
&on_websocket_setup_task_arg->task,
1452+
s_on_websocket_setup_task_fn,
1453+
(void *)on_websocket_setup_task_arg,
1454+
"on_websocket_setup_task");
1455+
aws_event_loop_schedule_task_now(connection->loop, &on_websocket_setup_task_arg->task);
14231456
}
14241457

14251458
/*******************************************************************************

tests/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ add_test_case(mqtt_validation_failure_connect_invalid_client_id_utf8)
108108
add_test_case(mqtt_validation_failure_invalid_will_topic_utf8)
109109
add_test_case(mqtt_validation_failure_invalid_username_utf8)
110110

111+
add_test_case(mqtt_websocket_failed_transform)
112+
111113
# Operation statistics tests
112114
add_test_case(mqtt_operation_statistics_simple_publish)
113115
add_test_case(mqtt_operation_statistics_offline_publish)

tests/v3/connection_state_test.c

+42
Original file line numberDiff line numberDiff line change
@@ -3968,3 +3968,45 @@ AWS_TEST_CASE_FIXTURE(
39683968
s_test_mqtt_validation_failure_invalid_username_utf8_fn,
39693969
s_clean_up_mqtt_server_fn,
39703970
&test_data)
3971+
3972+
static void s_mqtt_client_test_websocket_failed_transform(
3973+
struct aws_http_message *request,
3974+
void *user_data,
3975+
aws_mqtt_transform_websocket_handshake_complete_fn *complete_fn,
3976+
void *complete_ctx) {
3977+
3978+
struct mqtt_connection_state_test *state_test_data = user_data;
3979+
struct aws_mqtt_client_connection_311_impl *mqtt311_connection = state_test_data->mqtt_connection->impl;
3980+
/* This test should also perform a regression check: websocket transform failed on a non-eventloop thread does not
3981+
* cause crash. */
3982+
AWS_FATAL_ASSERT(!aws_event_loop_thread_is_callers_thread(mqtt311_connection->loop));
3983+
3984+
(*complete_fn)(request, AWS_ERROR_INVALID_STATE, complete_ctx);
3985+
}
3986+
3987+
/* Connection failure test where websocket MQTT channel establishment fails due to handshake transform failure */
3988+
static int s_test_mqtt_websocket_failed_transform_fn(struct aws_allocator *allocator, void *ctx) {
3989+
(void)allocator;
3990+
struct mqtt_connection_state_test *state_test_data = ctx;
3991+
3992+
struct aws_mqtt_connection_options connection_options = {
3993+
.socket_options = &state_test_data->socket_options,
3994+
};
3995+
3996+
aws_mqtt_client_connection_use_websockets(
3997+
state_test_data->mqtt_connection, s_mqtt_client_test_websocket_failed_transform, state_test_data, NULL, NULL);
3998+
3999+
ASSERT_SUCCESS(aws_mqtt_client_connection_connect(state_test_data->mqtt_connection, &connection_options));
4000+
aws_test311_wait_for_connection_to_fail(state_test_data);
4001+
4002+
ASSERT_INT_EQUALS(AWS_ERROR_INVALID_STATE, state_test_data->error);
4003+
4004+
return AWS_OP_SUCCESS;
4005+
}
4006+
4007+
AWS_TEST_CASE_FIXTURE(
4008+
mqtt_websocket_failed_transform,
4009+
s_setup_mqtt_server_fn,
4010+
s_test_mqtt_websocket_failed_transform_fn,
4011+
s_clean_up_mqtt_server_fn,
4012+
&test_data)

0 commit comments

Comments
 (0)