|
8 | 8 | #include <aws/common/clock.h> |
9 | 9 | #include <aws/common/encoding.h> |
10 | 10 | #include <aws/common/string.h> |
| 11 | +#include <aws/common/uuid.h> |
11 | 12 | #include <aws/io/channel_bootstrap.h> |
12 | 13 | #include <aws/io/event_loop.h> |
13 | | -#include <aws/io/stream.h> |
14 | 14 | #include <aws/mqtt/private/v5/mqtt5_client_impl.h> |
15 | 15 | #include <aws/mqtt/private/v5/mqtt5_utils.h> |
16 | 16 | #include <aws/mqtt/v5/mqtt5_client.h> |
@@ -3870,8 +3870,70 @@ struct aws_mqtt5_client_options_storage *aws_mqtt5_client_options_storage_new( |
3870 | 3870 | options_storage->topic_aliasing_options = *options->topic_aliasing_options; |
3871 | 3871 | } |
3872 | 3872 |
|
| 3873 | + struct aws_byte_buf auto_assign_id_buf; |
| 3874 | + AWS_ZERO_STRUCT(auto_assign_id_buf); |
| 3875 | + |
| 3876 | + struct aws_mqtt5_packet_connect_view connect_options = *options->connect_options; |
| 3877 | + if (connect_options.client_id.len == 0) { |
| 3878 | + if (options->extended_validation_and_flow_control_options == AWS_MQTT5_EVAFCO_AWS_IOT_CORE_DEFAULTS) { |
| 3879 | + /* |
| 3880 | + * We're (probably) using an SDK builder to create the client and there's no client id set. Assume this is |
| 3881 | + * targeting IoT Core. Iot Core is not compliant to the MQTT311/5 spec with regard to auto-assigned client |
| 3882 | + * ids. |
| 3883 | + * |
| 3884 | + * In particular, IoT Core makes a client id of the pattern "$GEN/[uuid]" but it forbids a client id of that |
| 3885 | + * pattern to be specified by the user. This is contrary to the spec that requires an auto-assigned client |
| 3886 | + * id to be able to reconnect using the same client id: |
| 3887 | + * |
| 3888 | + * "It MUST then process the CONNECT packet as if the Client had provided that unique ClientID, and MUST |
| 3889 | + * return the Assigned Client Identifier in the CONNACK packet." |
| 3890 | + * |
| 3891 | + * See (https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901059) for details. |
| 3892 | + * |
| 3893 | + * The result is that using auto assigned client ids with IoT Core leads to permanent reconnect failures |
| 3894 | + * because we use the client id value returned in the CONNACK for all subsequent connection attempts. This |
| 3895 | + * behavioral choice varies across MQTT clients, but I am firmly convinced it is proper. |
| 3896 | + * |
| 3897 | + * To work around this issue, when we think we're connecting to IoT Core (ie the condition above) and we |
| 3898 | + * don't have a client id, we generate one of the form "gen[uuid]" which will be able to successfully |
| 3899 | + * reconnect since it does not use the reserved prefix "$GEN/" |
| 3900 | + */ |
| 3901 | + aws_byte_buf_init(&auto_assign_id_buf, allocator, 64); |
| 3902 | + struct aws_byte_cursor auto_assign_prefix_cursor = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("gen"); |
| 3903 | + |
| 3904 | + aws_byte_buf_append(&auto_assign_id_buf, &auto_assign_prefix_cursor); |
| 3905 | + |
| 3906 | + struct aws_uuid uuid; |
| 3907 | + AWS_FATAL_ASSERT(aws_uuid_init(&uuid) == AWS_OP_SUCCESS); |
| 3908 | + |
| 3909 | + aws_uuid_to_str_compact(&uuid, &auto_assign_id_buf); |
| 3910 | + |
| 3911 | + connect_options.client_id = aws_byte_cursor_from_buf(&auto_assign_id_buf); |
| 3912 | + |
| 3913 | + AWS_LOGF_INFO( |
| 3914 | + AWS_LS_MQTT5_GENERAL, |
| 3915 | + "Inferring the server is IoT Core and no client id has been set. IoT Core's auto-assigned client ids " |
| 3916 | + "cannot be reconnected with. Avoiding this issue by locally setting the client id to \"" PRInSTR "\"", |
| 3917 | + AWS_BYTE_CURSOR_PRI(connect_options.client_id)); |
| 3918 | + } else { |
| 3919 | + /* |
| 3920 | + * Log the fact that we're not manually generating the client id in case someone turns off iot core |
| 3921 | + * validation and then sees reconnect failures. |
| 3922 | + */ |
| 3923 | + AWS_LOGF_WARN( |
| 3924 | + AWS_LS_MQTT5_GENERAL, |
| 3925 | + "Letting server assign the client id. If reconnects fail with a connect reason code of " |
| 3926 | + "AWS_MQTT5_CRC_CLIENT_IDENTIFIER_NOT_VALID (133), then consider manually setting the client id to a " |
| 3927 | + "UUID."); |
| 3928 | + } |
| 3929 | + } |
| 3930 | + |
3873 | 3931 | options_storage->connect = aws_mem_calloc(allocator, 1, sizeof(struct aws_mqtt5_packet_connect_storage)); |
3874 | | - if (aws_mqtt5_packet_connect_storage_init(options_storage->connect, allocator, options->connect_options)) { |
| 3932 | + int connect_storage_result = |
| 3933 | + aws_mqtt5_packet_connect_storage_init(options_storage->connect, allocator, &connect_options); |
| 3934 | + |
| 3935 | + aws_byte_buf_clean_up(&auto_assign_id_buf); |
| 3936 | + if (connect_storage_result != AWS_OP_SUCCESS) { |
3875 | 3937 | goto error; |
3876 | 3938 | } |
3877 | 3939 |
|
|
0 commit comments