Skip to content

Commit

Permalink
[#2955] Fix MQTT5 Connect Reason Codes
Browse files Browse the repository at this point in the history
MQTT5 defines new reason codes to be included in CONNACK packets when
connection establishment fails. The abstract adapter base class has been
changed accordingly.

Also added integration tests based on HiveMQ client for testing
connection establishment.
  • Loading branch information
sophokles73 committed Nov 19, 2024
1 parent 4de4ad5 commit eb04b19
Show file tree
Hide file tree
Showing 6 changed files with 1,202 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
import io.netty.handler.codec.mqtt.MqttConnectReturnCode;
import io.netty.handler.codec.mqtt.MqttProperties;
import io.netty.handler.codec.mqtt.MqttQoS;
import io.netty.handler.codec.mqtt.MqttVersion;
import io.opentracing.Span;
import io.opentracing.SpanContext;
import io.opentracing.log.Fields;
Expand Down Expand Up @@ -518,7 +519,7 @@ final void handleEndpointConnection(final MqttEndpoint endpoint) {
log.debug("rejecting connection request from client [clientId: {}], cause:",
endpoint.clientIdentifier(), t);

final MqttConnectReturnCode code = getConnectReturnCode(t);
final MqttConnectReturnCode code = getConnectReturnCode(t, endpoint);
rejectConnectionRequest(endpoint, code, span);
TracingHelper.logError(span, t);
}
Expand Down Expand Up @@ -1106,28 +1107,33 @@ final MqttDeviceEndpoint createMqttDeviceEndpoint(
return mqttDeviceEndpoint;
}

private static MqttConnectReturnCode getConnectReturnCode(final Throwable e) {
private static MqttConnectReturnCode getConnectReturnCode(final Throwable e, final MqttEndpoint endpoint) {

if (e instanceof MqttConnectionException) {
return ((MqttConnectionException) e).code();
final boolean isPreMqtt5 = ((int) MqttVersion.MQTT_5.protocolLevel()) > endpoint.protocolVersion();
if (e instanceof MqttConnectionException connectionException) {
return connectionException.code();
} else if (e instanceof AdapterConnectionsExceededException) {
return isPreMqtt5 ? MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE
: MqttConnectReturnCode.CONNECTION_REFUSED_QUOTA_EXCEEDED;
} else if (e instanceof AuthorizationException) {
if (e instanceof AdapterConnectionsExceededException) {
return MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE;
} else {
return MqttConnectReturnCode.CONNECTION_REFUSED_NOT_AUTHORIZED;
}
} else if (e instanceof ServiceInvocationException) {
switch (((ServiceInvocationException) e).getErrorCode()) {
return isPreMqtt5 ? MqttConnectReturnCode.CONNECTION_REFUSED_NOT_AUTHORIZED
: MqttConnectReturnCode.CONNECTION_REFUSED_NOT_AUTHORIZED_5;
} else if (e instanceof ServiceInvocationException exception) {
switch (exception.getErrorCode()) {
case HttpURLConnection.HTTP_UNAUTHORIZED:
case HttpURLConnection.HTTP_NOT_FOUND:
return MqttConnectReturnCode.CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD;
return isPreMqtt5 ? MqttConnectReturnCode.CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD
: MqttConnectReturnCode.CONNECTION_REFUSED_BAD_USERNAME_OR_PASSWORD;
case HttpURLConnection.HTTP_UNAVAILABLE:
return MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE;
return isPreMqtt5 ? MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE
: MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE_5;
default:
return MqttConnectReturnCode.CONNECTION_REFUSED_NOT_AUTHORIZED;
return isPreMqtt5 ? MqttConnectReturnCode.CONNECTION_REFUSED_NOT_AUTHORIZED
: MqttConnectReturnCode.CONNECTION_REFUSED_NOT_AUTHORIZED_5;
}
} else {
return MqttConnectReturnCode.CONNECTION_REFUSED_NOT_AUTHORIZED;
return isPreMqtt5 ? MqttConnectReturnCode.CONNECTION_REFUSED_NOT_AUTHORIZED
: MqttConnectReturnCode.CONNECTION_REFUSED_UNSPECIFIED_ERROR;
}
}

Expand Down
5 changes: 5 additions & 0 deletions bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,11 @@ quarkus.vertx.max-event-loop-execute-time=${max.event-loop.execute-time:20000}
</dependency>

<!-- Testing -->
<dependency>
<groupId>com.hivemq</groupId>
<artifactId>hivemq-mqtt-client</artifactId>
<version>1.3.3</version>
</dependency>
<dependency>
<groupId>org.eclipse.hono</groupId>
<artifactId>core-test-utils</artifactId>
Expand Down
4 changes: 4 additions & 0 deletions tests/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,10 @@
<artifactId>vertx-mqtt</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.hivemq</groupId>
<artifactId>hivemq-mqtt-client</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.californium</groupId>
<artifactId>californium-core</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2016, 2023 Contributors to the Eclipse Foundation
* Copyright (c) 2023 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
Expand Down Expand Up @@ -36,7 +36,7 @@
import io.vertx.mqtt.messages.MqttConnAckMessage;

/**
* Base class for MQTT adapter integration tests.
* Base class for MQTT adapter integration tests using MQTT 3.1.1.
*
*/
public abstract class MqttTestBase {
Expand Down Expand Up @@ -70,7 +70,7 @@ public abstract class MqttTestBase {
protected Context context;

/**
* Creates default AMQP client options.
* Creates default MQTT client options.
*/
@BeforeAll
public static void init() {
Expand Down
Loading

0 comments on commit eb04b19

Please sign in to comment.