com.hivemq.codec.encoder.mqtt3.Mqtt3SubackEncoder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hivemq-community-edition-embedded Show documentation
Show all versions of hivemq-community-edition-embedded Show documentation
HiveMQ CE is a Java-based open source MQTT broker that fully supports MQTT 3.x and MQTT 5
The newest version!
/*
* Copyright 2019-present HiveMQ GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hivemq.codec.encoder.mqtt3;
import com.hivemq.bootstrap.ClientConnectionContext;
import com.hivemq.extension.sdk.api.annotations.NotNull;
import com.hivemq.mqtt.handler.disconnect.MqttServerDisconnector;
import com.hivemq.mqtt.message.ProtocolVersion;
import com.hivemq.mqtt.message.mqtt5.Mqtt5UserProperties;
import com.hivemq.mqtt.message.reason.Mqtt5DisconnectReasonCode;
import com.hivemq.mqtt.message.reason.Mqtt5SubAckReasonCode;
import com.hivemq.mqtt.message.suback.SUBACK;
import io.netty.buffer.ByteBuf;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import static com.hivemq.mqtt.message.reason.Mqtt5SubAckReasonCode.GRANTED_QOS_0;
import static com.hivemq.mqtt.message.reason.Mqtt5SubAckReasonCode.GRANTED_QOS_1;
import static com.hivemq.mqtt.message.reason.Mqtt5SubAckReasonCode.GRANTED_QOS_2;
import static com.hivemq.mqtt.message.reason.Mqtt5SubAckReasonCode.UNSPECIFIED_ERROR;
public class Mqtt3SubackEncoder extends AbstractVariableHeaderLengthEncoder {
private static final Logger log = LoggerFactory.getLogger(Mqtt3SubackEncoder.class);
public static final int VARIABLE_HEADER_SIZE = 2;
private static final byte SUBACK_FIXED_HEADER = (byte) 0b1001_0000;
private final @NotNull MqttServerDisconnector mqttServerDisconnector;
public Mqtt3SubackEncoder(final @NotNull MqttServerDisconnector mqttServerDisconnector) {
this.mqttServerDisconnector = mqttServerDisconnector;
}
@Override
public void encode(
final @NotNull ClientConnectionContext clientConnectionContext,
final @NotNull SUBACK msg,
final @NotNull ByteBuf out) {
if (closedIfNotAllowed(clientConnectionContext, msg)) {
return;
}
out.writeByte(SUBACK_FIXED_HEADER);
final int remainingLength = msg.getRemainingLength();
createRemainingLength(remainingLength, out);
out.writeShort(msg.getPacketIdentifier());
for (final Mqtt5SubAckReasonCode granted : msg.getReasonCodes()) {
if (granted.getCode() >= 128) {
out.writeByte(UNSPECIFIED_ERROR.getCode());
} else {
out.writeByte(granted.getCode());
}
}
}
private boolean closedIfNotAllowed(
final @NotNull ClientConnectionContext clientConnectionContext, final @NotNull SUBACK msg) {
final ProtocolVersion protocolVersion = clientConnectionContext.getProtocolVersion();
final List grantedQos = msg.getReasonCodes();
if (grantedQos.isEmpty()) {
log.error("Tried to write a SUBACK with empty payload to a client. Disconnecting client (IP: {}).",
clientConnectionContext.getChannelIP().orElse("UNKNOWN"));
mqttServerDisconnector.disconnect(clientConnectionContext.getChannel(),
null,
//already logged
"Tried to write a SUBACK with empty payload to a client.",
Mqtt5DisconnectReasonCode.IMPLEMENTATION_SPECIFIC_ERROR,
null,
Mqtt5UserProperties.NO_USER_PROPERTIES,
false,
true);
return true;
}
for (final Mqtt5SubAckReasonCode granted : grantedQos) {
if ((granted.getCode() >= 128) && (protocolVersion == ProtocolVersion.MQTTv3_1)) {
log.error(
"Tried to write a failure code (0x80) to a MQTT 3.1 subscriber. Disconnecting client (IP: {}).",
clientConnectionContext.getChannelIP().orElse("UNKNOWN"));
mqttServerDisconnector.disconnect(clientConnectionContext.getChannel(),
null,
//already logged
"Tried to write a failure code (0x80) to a MQTT 3.1 subscriber.",
Mqtt5DisconnectReasonCode.IMPLEMENTATION_SPECIFIC_ERROR,
null,
Mqtt5UserProperties.NO_USER_PROPERTIES,
false,
true);
return true;
} else if (granted != GRANTED_QOS_0 &&
granted != GRANTED_QOS_1 &&
granted != GRANTED_QOS_2 &&
granted.getCode() < 128) {
log.error("Tried to write an invalid SUBACK return code to a subscriber. Disconnecting client (IP: {}).",
clientConnectionContext.getChannelIP().orElse("UNKNOWN"));
mqttServerDisconnector.disconnect(clientConnectionContext.getChannel(),
null,
//already logged
"Tried to write an invalid SUBACK return code to a subscriber.",
Mqtt5DisconnectReasonCode.IMPLEMENTATION_SPECIFIC_ERROR,
null,
Mqtt5UserProperties.NO_USER_PROPERTIES,
false,
true);
return true;
}
}
return false;
}
@Override
protected int remainingLength(final @NotNull SUBACK msg) {
return msg.getReasonCodes().size() + VARIABLE_HEADER_SIZE;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy