@@ -3512,15 +3512,39 @@ int aws_mqtt5_client_service_operational_state(struct aws_mqtt5_client_operation
35123512 return AWS_OP_SUCCESS ;
35133513}
35143514
3515+ static bool s_aws_mqtt5_client_validate_ack_reason_code_count (
3516+ const struct aws_mqtt5_operation * operation ,
3517+ enum aws_mqtt5_packet_type packet_type ,
3518+ const void * packet_view ) {
3519+
3520+ if (packet_type == AWS_MQTT5_PT_SUBACK ) {
3521+ const struct aws_mqtt5_packet_subscribe_view * subscribe_view = operation -> packet_view ;
3522+ const struct aws_mqtt5_packet_suback_view * suback_view = packet_view ;
3523+
3524+ return subscribe_view -> subscription_count == suback_view -> reason_code_count ;
3525+ }
3526+
3527+ if (packet_type == AWS_MQTT5_PT_UNSUBACK ) {
3528+ const struct aws_mqtt5_packet_unsubscribe_view * unsubscribe_view = operation -> packet_view ;
3529+ const struct aws_mqtt5_packet_unsuback_view * unsuback_view = packet_view ;
3530+
3531+ return unsubscribe_view -> topic_filter_count == unsuback_view -> reason_code_count ;
3532+ }
3533+
3534+ return true;
3535+ }
3536+
35153537void aws_mqtt5_client_operational_state_handle_ack (
35163538 struct aws_mqtt5_client_operational_state * client_operational_state ,
35173539 aws_mqtt5_packet_id_t packet_id ,
35183540 enum aws_mqtt5_packet_type packet_type ,
35193541 const void * packet_view ,
35203542 int error_code ) {
35213543
3544+ struct aws_mqtt5_client * client = client_operational_state -> client ;
3545+
35223546 if (packet_type == AWS_MQTT5_PT_PUBACK ) {
3523- aws_mqtt5_client_flow_control_state_on_puback (client_operational_state -> client );
3547+ aws_mqtt5_client_flow_control_state_on_puback (client );
35243548 }
35253549
35263550 struct aws_hash_element * elem = NULL ;
@@ -3530,23 +3554,45 @@ void aws_mqtt5_client_operational_state_handle_ack(
35303554 AWS_LOGF_ERROR (
35313555 AWS_LS_MQTT5_CLIENT ,
35323556 "id=%p: received an ACK for an unknown operation with id %d" ,
3533- (void * )client_operational_state -> client ,
3557+ (void * )client ,
35343558 (int )packet_id );
35353559 return ;
35363560 } else {
3537- AWS_LOGF_TRACE (
3538- AWS_LS_MQTT5_CLIENT ,
3539- "id=%p: Processing ACK with id %d" ,
3540- (void * )client_operational_state -> client ,
3541- (int )packet_id );
3561+ AWS_LOGF_TRACE (AWS_LS_MQTT5_CLIENT , "id=%p: Processing ACK with id %d" , (void * )client , (int )packet_id );
35423562 }
35433563
35443564 struct aws_mqtt5_operation * operation = elem -> value ;
35453565
35463566 aws_linked_list_remove (& operation -> node );
35473567 aws_hash_table_remove (& client_operational_state -> unacked_operations_table , & packet_id , NULL , NULL );
35483568
3549- s_complete_operation (client_operational_state -> client , operation , error_code , packet_type , packet_view );
3569+ if (!s_aws_mqtt5_client_validate_ack_reason_code_count (operation , packet_type , packet_view )) {
3570+ AWS_LOGF_ERROR (
3571+ AWS_LS_MQTT5_CLIENT ,
3572+ "id=%p: received a %s with a reason code count that does not match the acknowledged request; treating as a "
3573+ "protocol error and disconnecting" ,
3574+ (void * )client ,
3575+ aws_mqtt5_packet_type_to_c_string (packet_type ));
3576+
3577+ /*
3578+ * We must complete the operation explicitly rather than relying on the shutdown's operational-state reset:
3579+ * a subscribe/unsubscribe is retainable under the default offline queue policy, so the reset would requeue it
3580+ * for retry, potentially producing an endless disconnect/reconnect/resubscribe loop against a misbehaving
3581+ * broker.
3582+ */
3583+ s_complete_operation (client , operation , AWS_ERROR_MQTT5_DECODE_PROTOCOL_ERROR , AWS_MQTT5_PT_NONE , NULL );
3584+
3585+ if (s_should_client_disconnect_cleanly (client )) {
3586+ s_aws_mqtt5_client_shutdown_channel_clean (
3587+ client , AWS_ERROR_MQTT5_DECODE_PROTOCOL_ERROR , AWS_MQTT5_DRC_PROTOCOL_ERROR );
3588+ } else {
3589+ s_aws_mqtt5_client_shutdown_channel (client , AWS_ERROR_MQTT5_DECODE_PROTOCOL_ERROR );
3590+ }
3591+
3592+ return ;
3593+ }
3594+
3595+ s_complete_operation (client , operation , error_code , packet_type , packet_view );
35503596}
35513597
35523598bool aws_mqtt5_client_are_negotiated_settings_valid (const struct aws_mqtt5_client * client ) {
0 commit comments