
com.hivemq.codec.decoder.mqtt5.Mqtt5DisconnectDecoder 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
/*
* 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.decoder.mqtt5;
import com.google.common.collect.ImmutableList;
import com.hivemq.bootstrap.ClientConnectionContext;
import com.hivemq.bootstrap.ioc.lazysingleton.LazySingleton;
import com.hivemq.codec.decoder.AbstractMqttDecoder;
import com.hivemq.configuration.service.FullConfigurationService;
import com.hivemq.extension.sdk.api.annotations.NotNull;
import com.hivemq.extension.sdk.api.annotations.Nullable;
import com.hivemq.mqtt.handler.disconnect.MqttServerDisconnector;
import com.hivemq.mqtt.message.MessageType;
import com.hivemq.mqtt.message.disconnect.DISCONNECT;
import com.hivemq.mqtt.message.mqtt5.Mqtt5UserProperties;
import com.hivemq.mqtt.message.mqtt5.MqttUserProperty;
import com.hivemq.mqtt.message.reason.Mqtt5DisconnectReasonCode;
import com.hivemq.util.ReasonStrings;
import io.netty.buffer.ByteBuf;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import static com.hivemq.mqtt.message.disconnect.DISCONNECT.SESSION_EXPIRY_NOT_SET;
import static com.hivemq.mqtt.message.mqtt5.MessageProperties.REASON_STRING;
import static com.hivemq.mqtt.message.mqtt5.MessageProperties.SERVER_REFERENCE;
import static com.hivemq.mqtt.message.mqtt5.MessageProperties.SESSION_EXPIRY_INTERVAL;
import static com.hivemq.mqtt.message.mqtt5.MessageProperties.USER_PROPERTY;
@LazySingleton
public class Mqtt5DisconnectDecoder extends AbstractMqttDecoder {
private static final Logger log = LoggerFactory.getLogger(Mqtt5DisconnectDecoder.class);
private final long maxSessionExpiryInterval;
@Inject
public Mqtt5DisconnectDecoder(
final @NotNull MqttServerDisconnector disconnector,
final @NotNull FullConfigurationService configurationService) {
super(disconnector, configurationService);
maxSessionExpiryInterval = configurationService.mqttConfiguration().maxSessionExpiryInterval();
}
@Override
public @Nullable DISCONNECT decode(
final @NotNull ClientConnectionContext clientConnectionContext,
final @NotNull ByteBuf buf,
final byte header) {
if (!validateHeader(header)) {
disconnectByInvalidFixedHeader(clientConnectionContext, MessageType.DISCONNECT);
return null;
}
//nothing more to read => normal disconnect
if (!buf.isReadable()) {
return new DISCONNECT(Mqtt5DisconnectReasonCode.NORMAL_DISCONNECTION,
null,
Mqtt5UserProperties.NO_USER_PROPERTIES,
null,
SESSION_EXPIRY_NOT_SET);
}
final Mqtt5DisconnectReasonCode reasonCode = Mqtt5DisconnectReasonCode.fromCode(buf.readUnsignedByte());
if (reasonCode == null) {
disconnectByInvalidReasonCode(clientConnectionContext, MessageType.DISCONNECT);
return null;
}
//nothing more to read => disconnect with reason code
if (!buf.isReadable()) {
return new DISCONNECT(reasonCode,
null,
Mqtt5UserProperties.NO_USER_PROPERTIES,
null,
SESSION_EXPIRY_NOT_SET);
}
final int propertiesLength =
decodePropertiesLengthNoPayload(clientConnectionContext, buf, MessageType.DISCONNECT);
if (propertiesLength == DISCONNECTED) {
return null;
}
long sessionExpiryInterval = SESSION_EXPIRY_NOT_SET;
String serverReference = null;
String reasonString = null;
ImmutableList.Builder userPropertiesBuilder = null;
//read properties => disconnect with reason code and properties
while (buf.isReadable()) {
final int propertyIdentifier = buf.readByte();
switch (propertyIdentifier) {
case SESSION_EXPIRY_INTERVAL:
sessionExpiryInterval = decodeSessionExpiryInterval(clientConnectionContext,
buf,
sessionExpiryInterval,
SESSION_EXPIRY_NOT_SET,
MessageType.DISCONNECT);
if (sessionExpiryInterval == DISCONNECTED) {
return null;
}
final Long sessionExpiryIntervalFromChannel =
clientConnectionContext.getClientSessionExpiryInterval();
if ((sessionExpiryInterval != 0) && (sessionExpiryIntervalFromChannel == 0)) {
disconnector.disconnect(clientConnectionContext.getChannel(),
"A client (IP: {}) sent a DISCONNECT with session expiry interval, but session expiry interval was set to zero at CONNECT. This is not allowed. Disconnecting client.",
"DISCONNECT with session expiry interval, but session expiry interval was set to zero at CONNECT.",
Mqtt5DisconnectReasonCode.PROTOCOL_ERROR,
ReasonStrings.DISCONNECT_PROTOCOL_ERROR_SESSION_EXPIRY);
return null;
}
//it must not be greater than the configured maximum
if (sessionExpiryInterval > maxSessionExpiryInterval) {
if (log.isDebugEnabled()) {
log.debug(
"A client (IP: {}) sent a DISCONNECT with a session expiry interval of ('{}'), which is larger than configured maximum of '{}'",
clientConnectionContext.getChannelIP().orElse("UNKNOWN"),
sessionExpiryInterval,
maxSessionExpiryInterval);
}
sessionExpiryInterval = maxSessionExpiryInterval;
}
break;
case SERVER_REFERENCE:
serverReference = decodeServerReference(clientConnectionContext,
buf,
serverReference,
MessageType.DISCONNECT);
if (serverReference == null) {
return null;
}
break;
case REASON_STRING:
reasonString =
decodeReasonString(clientConnectionContext, buf, reasonString, MessageType.DISCONNECT);
if (reasonString == null) {
return null;
}
break;
case USER_PROPERTY:
userPropertiesBuilder = readUserProperty(clientConnectionContext,
buf,
userPropertiesBuilder,
MessageType.DISCONNECT);
if (userPropertiesBuilder == null) {
return null;
}
break;
default:
disconnectByInvalidPropertyIdentifier(clientConnectionContext,
propertyIdentifier,
MessageType.DISCONNECT);
return null;
}
}
final Mqtt5UserProperties userProperties = Mqtt5UserProperties.build(userPropertiesBuilder);
if (invalidUserPropertiesLength(clientConnectionContext, MessageType.DISCONNECT, userProperties)) {
return null;
}
return new DISCONNECT(reasonCode, reasonString, userProperties, serverReference, sessionExpiryInterval);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy