wildfire chat server source initial submit
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2014 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you 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 io.netty.handler.codec.mqtt;
|
||||
|
||||
import io.netty.handler.codec.DecoderException;
|
||||
|
||||
final class MqttCodecUtil {
|
||||
|
||||
private static final char[] TOPIC_WILDCARDS = {'#', '+'};
|
||||
private static final int MIN_CLIENT_ID_LENGTH = 1;
|
||||
private static final int MAX_CLIENT_ID_LENGTH = 23;
|
||||
|
||||
static boolean isValidPublishTopicName(String topicName) {
|
||||
// publish topic name must not contain any wildcard
|
||||
for (char c : TOPIC_WILDCARDS) {
|
||||
if (topicName.indexOf(c) >= 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static boolean isValidMessageId(int messageId) {
|
||||
return messageId != 0;
|
||||
}
|
||||
|
||||
static boolean isValidClientId(MqttVersion mqttVersion, String clientId) {
|
||||
if (mqttVersion == MqttVersion.MQTT_3_1) {
|
||||
return clientId != null && clientId.length() >= MIN_CLIENT_ID_LENGTH &&
|
||||
clientId.length() <= MAX_CLIENT_ID_LENGTH;
|
||||
}
|
||||
if (mqttVersion == MqttVersion.MQTT_3_1_1) {
|
||||
// In 3.1.3.1 Client Identifier of MQTT 3.1.1 specification, The Server MAY allow ClientId’s
|
||||
// that contain more than 23 encoded bytes. And, The Server MAY allow zero-length ClientId.
|
||||
return clientId != null;
|
||||
}
|
||||
throw new IllegalArgumentException(mqttVersion + " is unknown mqtt version");
|
||||
}
|
||||
|
||||
static MqttFixedHeader validateFixedHeader(MqttFixedHeader mqttFixedHeader) {
|
||||
switch (mqttFixedHeader.messageType()) {
|
||||
case PUBREL:
|
||||
case SUBSCRIBE:
|
||||
case UNSUBSCRIBE:
|
||||
if (mqttFixedHeader.qosLevel() != MqttQoS.AT_LEAST_ONCE) {
|
||||
throw new DecoderException(mqttFixedHeader.messageType().name() + " message must have QoS 1");
|
||||
}
|
||||
default:
|
||||
return mqttFixedHeader;
|
||||
}
|
||||
}
|
||||
|
||||
static MqttFixedHeader resetUnusedFields(MqttFixedHeader mqttFixedHeader) {
|
||||
switch (mqttFixedHeader.messageType()) {
|
||||
case CONNECT:
|
||||
case CONNACK:
|
||||
case PUBACK:
|
||||
case PUBREC:
|
||||
case PUBCOMP:
|
||||
case SUBACK:
|
||||
case UNSUBACK:
|
||||
case PINGREQ:
|
||||
case PINGRESP:
|
||||
//case DISCONNECT:
|
||||
if (mqttFixedHeader.isDup() ||
|
||||
mqttFixedHeader.qosLevel() != MqttQoS.AT_MOST_ONCE ||
|
||||
mqttFixedHeader.isRetain()) {
|
||||
return new MqttFixedHeader(
|
||||
mqttFixedHeader.messageType(),
|
||||
false,
|
||||
MqttQoS.AT_MOST_ONCE,
|
||||
false,
|
||||
mqttFixedHeader.remainingLength());
|
||||
}
|
||||
return mqttFixedHeader;
|
||||
case PUBREL:
|
||||
case SUBSCRIBE:
|
||||
case UNSUBSCRIBE:
|
||||
if (mqttFixedHeader.isRetain()) {
|
||||
return new MqttFixedHeader(
|
||||
mqttFixedHeader.messageType(),
|
||||
mqttFixedHeader.isDup(),
|
||||
mqttFixedHeader.qosLevel(),
|
||||
false,
|
||||
mqttFixedHeader.remainingLength());
|
||||
}
|
||||
return mqttFixedHeader;
|
||||
default:
|
||||
return mqttFixedHeader;
|
||||
}
|
||||
}
|
||||
|
||||
private MqttCodecUtil() { }
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2014 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you 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 io.netty.handler.codec.mqtt;
|
||||
|
||||
/**
|
||||
* See <a href="http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#connack">MQTTV3.1/connack</a>
|
||||
*/
|
||||
public final class MqttConnAckMessage extends MqttMessage {
|
||||
|
||||
public MqttConnAckMessage(MqttFixedHeader mqttFixedHeader, MqttConnAckVariableHeader variableHeader) {
|
||||
super(mqttFixedHeader, variableHeader);
|
||||
}
|
||||
|
||||
public MqttConnAckMessage(MqttFixedHeader mqttFixedHeader, MqttConnAckVariableHeader variableHeader, MqttConnectAckPayload payload) {
|
||||
super(mqttFixedHeader, variableHeader, payload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MqttConnAckVariableHeader variableHeader() {
|
||||
return (MqttConnAckVariableHeader) super.variableHeader();
|
||||
}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2014 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you 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 io.netty.handler.codec.mqtt;
|
||||
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
/**
|
||||
* Variable header of {@link MqttConnectMessage}
|
||||
*/
|
||||
public final class MqttConnAckVariableHeader {
|
||||
|
||||
private final MqttConnectReturnCode connectReturnCode;
|
||||
|
||||
private final boolean sessionPresent;
|
||||
|
||||
public MqttConnAckVariableHeader(MqttConnectReturnCode connectReturnCode, boolean sessionPresent) {
|
||||
this.connectReturnCode = connectReturnCode;
|
||||
this.sessionPresent = sessionPresent;
|
||||
}
|
||||
|
||||
public MqttConnectReturnCode connectReturnCode() {
|
||||
return connectReturnCode;
|
||||
}
|
||||
|
||||
public boolean isSessionPresent() {
|
||||
return sessionPresent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder(StringUtil.simpleClassName(this))
|
||||
.append('[')
|
||||
.append("connectReturnCode=").append(connectReturnCode)
|
||||
.append(", sessionPresent=").append(sessionPresent)
|
||||
.append(']')
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2014 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you 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 io.netty.handler.codec.mqtt;
|
||||
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
/**
|
||||
* Payload of {@link MqttConnectMessage}
|
||||
*/
|
||||
public final class MqttConnectAckPayload {
|
||||
|
||||
private final byte[] data;
|
||||
|
||||
public MqttConnectAckPayload(
|
||||
byte[] data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder(StringUtil.simpleClassName(this))
|
||||
.append('[')
|
||||
.append("data=").append(data)
|
||||
.append(']')
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2014 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you 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 io.netty.handler.codec.mqtt;
|
||||
|
||||
/**
|
||||
* See <a href="http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#connect">MQTTV3.1/connect</a>
|
||||
*/
|
||||
public final class MqttConnectMessage extends MqttMessage {
|
||||
|
||||
public MqttConnectMessage(
|
||||
MqttFixedHeader mqttFixedHeader,
|
||||
MqttConnectVariableHeader variableHeader,
|
||||
MqttConnectPayload payload) {
|
||||
super(mqttFixedHeader, variableHeader, payload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MqttConnectVariableHeader variableHeader() {
|
||||
return (MqttConnectVariableHeader) super.variableHeader();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MqttConnectPayload payload() {
|
||||
return (MqttConnectPayload) super.payload();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2014 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you 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 io.netty.handler.codec.mqtt;
|
||||
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
/**
|
||||
* Payload of {@link MqttConnectMessage}
|
||||
*/
|
||||
public final class MqttConnectPayload {
|
||||
|
||||
private final String clientIdentifier;
|
||||
private final String willTopic;
|
||||
private final String willMessage;
|
||||
private final String userName;
|
||||
private final byte[] password;
|
||||
|
||||
public MqttConnectPayload(
|
||||
String clientIdentifier,
|
||||
String willTopic,
|
||||
String willMessage,
|
||||
String userName,
|
||||
byte[] password) {
|
||||
this.clientIdentifier = clientIdentifier;
|
||||
this.willTopic = willTopic;
|
||||
this.willMessage = willMessage;
|
||||
this.userName = userName;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String clientIdentifier() {
|
||||
return clientIdentifier;
|
||||
}
|
||||
|
||||
public String willTopic() {
|
||||
return willTopic;
|
||||
}
|
||||
|
||||
public String willMessage() {
|
||||
return willMessage;
|
||||
}
|
||||
|
||||
public String userName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
public byte[] password() {
|
||||
return password;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder(StringUtil.simpleClassName(this))
|
||||
.append('[')
|
||||
.append("clientIdentifier=").append(clientIdentifier)
|
||||
.append(", willTopic=").append(willTopic)
|
||||
.append(", willMessage=").append(willMessage)
|
||||
.append(", userName=").append(userName)
|
||||
.append(", password=").append(password)
|
||||
.append(']')
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2014 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you 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 io.netty.handler.codec.mqtt;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Return Code of {@link MqttConnAckMessage}
|
||||
*/
|
||||
public enum MqttConnectReturnCode {
|
||||
CONNECTION_ACCEPTED((byte) 0x00),
|
||||
CONNECTION_REFUSED_UNACCEPTABLE_PROTOCOL_VERSION((byte) 0X01),
|
||||
CONNECTION_REFUSED_IDENTIFIER_REJECTED((byte) 0x02),
|
||||
CONNECTION_REFUSED_SERVER_UNAVAILABLE((byte) 0x03),
|
||||
CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD((byte) 0x04),
|
||||
CONNECTION_REFUSED_NOT_AUTHORIZED((byte) 0x05),
|
||||
CONNECTION_REFUSED_UNEXPECT_NODE((byte) 0X06),
|
||||
CONNECTION_REFUSED_SESSION_NOT_EXIST((byte) 0x07);
|
||||
|
||||
private static final Map<Byte, MqttConnectReturnCode> VALUE_TO_CODE_MAP;
|
||||
|
||||
static {
|
||||
final Map<Byte, MqttConnectReturnCode> valueMap = new HashMap<Byte, MqttConnectReturnCode>();
|
||||
for (MqttConnectReturnCode code: values()) {
|
||||
valueMap.put(code.byteValue, code);
|
||||
}
|
||||
VALUE_TO_CODE_MAP = Collections.unmodifiableMap(valueMap);
|
||||
}
|
||||
|
||||
private final byte byteValue;
|
||||
|
||||
MqttConnectReturnCode(byte byteValue) {
|
||||
this.byteValue = byteValue;
|
||||
}
|
||||
|
||||
public byte byteValue() {
|
||||
return byteValue;
|
||||
}
|
||||
|
||||
public static MqttConnectReturnCode valueOf(byte b) {
|
||||
if (VALUE_TO_CODE_MAP.containsKey(b)) {
|
||||
return VALUE_TO_CODE_MAP.get(b);
|
||||
}
|
||||
throw new IllegalArgumentException("unknown connect return code: " + (b & 0xFF));
|
||||
}
|
||||
}
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2014 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you 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 io.netty.handler.codec.mqtt;
|
||||
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
/**
|
||||
* Variable Header for the {@link MqttConnectMessage}
|
||||
*/
|
||||
public final class MqttConnectVariableHeader {
|
||||
|
||||
private final String name;
|
||||
private final int version;
|
||||
private final boolean hasUserName;
|
||||
private final boolean hasPassword;
|
||||
private final boolean isWillRetain;
|
||||
private final int willQos;
|
||||
private final boolean isWillFlag;
|
||||
private final boolean isCleanSession;
|
||||
private final int keepAliveTimeSeconds;
|
||||
|
||||
public MqttConnectVariableHeader(
|
||||
String name,
|
||||
int version,
|
||||
boolean hasUserName,
|
||||
boolean hasPassword,
|
||||
boolean isWillRetain,
|
||||
int willQos,
|
||||
boolean isWillFlag,
|
||||
boolean isCleanSession,
|
||||
int keepAliveTimeSeconds) {
|
||||
this.name = name;
|
||||
this.version = version;
|
||||
this.hasUserName = hasUserName;
|
||||
this.hasPassword = hasPassword;
|
||||
this.isWillRetain = isWillRetain;
|
||||
this.willQos = willQos;
|
||||
this.isWillFlag = isWillFlag;
|
||||
this.isCleanSession = isCleanSession;
|
||||
this.keepAliveTimeSeconds = keepAliveTimeSeconds;
|
||||
}
|
||||
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public int version() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public boolean hasUserName() {
|
||||
return hasUserName;
|
||||
}
|
||||
|
||||
public boolean hasPassword() {
|
||||
return hasPassword;
|
||||
}
|
||||
|
||||
public boolean isWillRetain() {
|
||||
return isWillRetain;
|
||||
}
|
||||
|
||||
public int willQos() {
|
||||
return willQos;
|
||||
}
|
||||
|
||||
public boolean isWillFlag() {
|
||||
return isWillFlag;
|
||||
}
|
||||
|
||||
public boolean isCleanSession() {
|
||||
return isCleanSession;
|
||||
}
|
||||
|
||||
public int keepAliveTimeSeconds() {
|
||||
return keepAliveTimeSeconds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder(StringUtil.simpleClassName(this))
|
||||
.append('[')
|
||||
.append("name=").append(name)
|
||||
.append(", version=").append(version)
|
||||
.append(", hasUserName=").append(hasUserName)
|
||||
.append(", hasPassword=").append(hasPassword)
|
||||
.append(", isWillRetain=").append(isWillRetain)
|
||||
.append(", isWillFlag=").append(isWillFlag)
|
||||
.append(", isCleanSession=").append(isCleanSession)
|
||||
.append(", keepAliveTimeSeconds=").append(keepAliveTimeSeconds)
|
||||
.append(']')
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,493 @@
|
||||
/*
|
||||
* Copyright 2014 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you 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 io.netty.handler.codec.mqtt;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.DecoderException;
|
||||
import io.netty.handler.codec.ReplayingDecoder;
|
||||
import io.netty.handler.codec.mqtt.MqttDecoder.DecoderState;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static io.netty.handler.codec.mqtt.MqttCodecUtil.isValidClientId;
|
||||
import static io.netty.handler.codec.mqtt.MqttCodecUtil.isValidMessageId;
|
||||
import static io.netty.handler.codec.mqtt.MqttCodecUtil.isValidPublishTopicName;
|
||||
import static io.netty.handler.codec.mqtt.MqttCodecUtil.resetUnusedFields;
|
||||
import static io.netty.handler.codec.mqtt.MqttCodecUtil.validateFixedHeader;
|
||||
|
||||
/**
|
||||
* Decodes Mqtt messages from bytes, following
|
||||
* <a href="http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html">
|
||||
* the MQTT protocol specification v3.1</a>
|
||||
*/
|
||||
public final class MqttDecoder extends ReplayingDecoder<DecoderState> {
|
||||
|
||||
private static final int DEFAULT_MAX_BYTES_IN_MESSAGE = 262144; //256K
|
||||
|
||||
/**
|
||||
* States of the decoder.
|
||||
* We start at READ_FIXED_HEADER, followed by
|
||||
* READ_VARIABLE_HEADER and finally READ_PAYLOAD.
|
||||
*/
|
||||
enum DecoderState {
|
||||
READ_FIXED_HEADER,
|
||||
READ_VARIABLE_HEADER,
|
||||
READ_PAYLOAD,
|
||||
BAD_MESSAGE,
|
||||
}
|
||||
|
||||
private MqttFixedHeader mqttFixedHeader;
|
||||
private Object variableHeader;
|
||||
private int bytesRemainingInVariablePart;
|
||||
|
||||
private final int maxBytesInMessage;
|
||||
|
||||
public MqttDecoder() {
|
||||
this(DEFAULT_MAX_BYTES_IN_MESSAGE);
|
||||
}
|
||||
|
||||
public MqttDecoder(int maxBytesInMessage) {
|
||||
super(DecoderState.READ_FIXED_HEADER);
|
||||
this.maxBytesInMessage = maxBytesInMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) throws Exception {
|
||||
switch (state()) {
|
||||
case READ_FIXED_HEADER:
|
||||
mqttFixedHeader = decodeFixedHeader(buffer);
|
||||
bytesRemainingInVariablePart = mqttFixedHeader.remainingLength();
|
||||
checkpoint(DecoderState.READ_VARIABLE_HEADER);
|
||||
// fall through
|
||||
|
||||
case READ_VARIABLE_HEADER: try {
|
||||
if (bytesRemainingInVariablePart > maxBytesInMessage) {
|
||||
throw new DecoderException("too large message: " + bytesRemainingInVariablePart + " bytes");
|
||||
}
|
||||
final Result<?> decodedVariableHeader = decodeVariableHeader(buffer, mqttFixedHeader);
|
||||
variableHeader = decodedVariableHeader.value;
|
||||
bytesRemainingInVariablePart -= decodedVariableHeader.numberOfBytesConsumed;
|
||||
checkpoint(DecoderState.READ_PAYLOAD);
|
||||
// fall through
|
||||
} catch (Exception cause) {
|
||||
out.add(invalidMessage(cause));
|
||||
return;
|
||||
}
|
||||
|
||||
case READ_PAYLOAD: try {
|
||||
final Result<?> decodedPayload =
|
||||
decodePayload(
|
||||
buffer,
|
||||
mqttFixedHeader.messageType(),
|
||||
bytesRemainingInVariablePart,
|
||||
variableHeader);
|
||||
bytesRemainingInVariablePart -= decodedPayload.numberOfBytesConsumed;
|
||||
if (bytesRemainingInVariablePart != 0) {
|
||||
throw new DecoderException(
|
||||
"non-zero remaining payload bytes: " +
|
||||
bytesRemainingInVariablePart + " (" + mqttFixedHeader.messageType() + ')');
|
||||
}
|
||||
checkpoint(DecoderState.READ_FIXED_HEADER);
|
||||
MqttMessage message = MqttMessageFactory.newMessage(
|
||||
mqttFixedHeader, variableHeader, decodedPayload.value);
|
||||
mqttFixedHeader = null;
|
||||
variableHeader = null;
|
||||
out.add(message);
|
||||
break;
|
||||
} catch (Exception cause) {
|
||||
out.add(invalidMessage(cause));
|
||||
return;
|
||||
}
|
||||
|
||||
case BAD_MESSAGE:
|
||||
// Keep discarding until disconnection.
|
||||
buffer.skipBytes(actualReadableBytes());
|
||||
break;
|
||||
|
||||
default:
|
||||
// Shouldn't reach here.
|
||||
throw new Error();
|
||||
}
|
||||
}
|
||||
|
||||
private MqttMessage invalidMessage(Throwable cause) {
|
||||
checkpoint(DecoderState.BAD_MESSAGE);
|
||||
return MqttMessageFactory.newInvalidMessage(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes the fixed header. It's one byte for the flags and then variable bytes for the remaining length.
|
||||
*
|
||||
* @param buffer the buffer to decode from
|
||||
* @return the fixed header
|
||||
*/
|
||||
private static MqttFixedHeader decodeFixedHeader(ByteBuf buffer) {
|
||||
short b1 = buffer.readUnsignedByte();
|
||||
|
||||
MqttMessageType messageType = MqttMessageType.valueOf(b1 >> 4);
|
||||
boolean dupFlag = (b1 & 0x08) == 0x08;
|
||||
int qosLevel = (b1 & 0x06) >> 1;
|
||||
boolean retain = (b1 & 0x01) != 0;
|
||||
|
||||
int remainingLength = 0;
|
||||
int multiplier = 1;
|
||||
short digit;
|
||||
int loops = 0;
|
||||
do {
|
||||
digit = buffer.readUnsignedByte();
|
||||
remainingLength += (digit & 127) * multiplier;
|
||||
multiplier *= 128;
|
||||
loops++;
|
||||
} while ((digit & 128) != 0 && loops < 4);
|
||||
|
||||
// MQTT protocol limits Remaining Length to 4 bytes
|
||||
if (loops == 4 && (digit & 128) != 0) {
|
||||
throw new DecoderException("remaining length exceeds 4 digits (" + messageType + ')');
|
||||
}
|
||||
MqttFixedHeader decodedFixedHeader =
|
||||
new MqttFixedHeader(messageType, dupFlag, MqttQoS.valueOf(qosLevel), retain, remainingLength);
|
||||
return validateFixedHeader(resetUnusedFields(decodedFixedHeader));
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes the variable header (if any)
|
||||
* @param buffer the buffer to decode from
|
||||
* @param mqttFixedHeader MqttFixedHeader of the same message
|
||||
* @return the variable header
|
||||
*/
|
||||
private static Result<?> decodeVariableHeader(ByteBuf buffer, MqttFixedHeader mqttFixedHeader) {
|
||||
switch (mqttFixedHeader.messageType()) {
|
||||
case CONNECT:
|
||||
return decodeConnectionVariableHeader(buffer);
|
||||
|
||||
case CONNACK:
|
||||
return decodeConnAckVariableHeader(buffer);
|
||||
|
||||
case SUBSCRIBE:
|
||||
case UNSUBSCRIBE:
|
||||
case SUBACK:
|
||||
case UNSUBACK:
|
||||
case PUBACK:
|
||||
case PUBREC:
|
||||
case PUBCOMP:
|
||||
case PUBREL:
|
||||
return decodeMessageIdVariableHeader(buffer);
|
||||
|
||||
case PUBLISH:
|
||||
return decodePublishVariableHeader(buffer, mqttFixedHeader);
|
||||
|
||||
case PINGREQ:
|
||||
case PINGRESP:
|
||||
case DISCONNECT:
|
||||
// Empty variable header
|
||||
return new Result<Object>(null, 0);
|
||||
}
|
||||
return new Result<Object>(null, 0); //should never reach here
|
||||
}
|
||||
|
||||
private static Result<MqttConnectVariableHeader> decodeConnectionVariableHeader(ByteBuf buffer) {
|
||||
final Result<String> protoString = decodeString(buffer);
|
||||
int numberOfBytesConsumed = protoString.numberOfBytesConsumed;
|
||||
|
||||
final byte protocolLevel = buffer.readByte();
|
||||
numberOfBytesConsumed += 1;
|
||||
|
||||
final MqttVersion mqttVersion = MqttVersion.fromProtocolNameAndLevel(protoString.value, protocolLevel);
|
||||
|
||||
final int b1 = buffer.readUnsignedByte();
|
||||
numberOfBytesConsumed += 1;
|
||||
|
||||
final Result<Integer> keepAlive = decodeMsbLsb(buffer);
|
||||
numberOfBytesConsumed += keepAlive.numberOfBytesConsumed;
|
||||
|
||||
final boolean hasUserName = (b1 & 0x80) == 0x80;
|
||||
final boolean hasPassword = (b1 & 0x40) == 0x40;
|
||||
final boolean willRetain = (b1 & 0x20) == 0x20;
|
||||
final int willQos = (b1 & 0x18) >> 3;
|
||||
final boolean willFlag = (b1 & 0x04) == 0x04;
|
||||
final boolean cleanSession = (b1 & 0x02) == 0x02;
|
||||
if (mqttVersion == MqttVersion.MQTT_3_1_1) {
|
||||
final boolean zeroReservedFlag = (b1 & 0x01) == 0x0;
|
||||
if (!zeroReservedFlag) {
|
||||
// MQTT v3.1.1: The Server MUST validate that the reserved flag in the CONNECT Control Packet is
|
||||
// set to zero and disconnect the Client if it is not zero.
|
||||
// See http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc385349230
|
||||
throw new DecoderException("non-zero reserved flag");
|
||||
}
|
||||
}
|
||||
|
||||
final MqttConnectVariableHeader mqttConnectVariableHeader = new MqttConnectVariableHeader(
|
||||
mqttVersion.protocolName(),
|
||||
mqttVersion.protocolLevel(),
|
||||
hasUserName,
|
||||
hasPassword,
|
||||
willRetain,
|
||||
willQos,
|
||||
willFlag,
|
||||
cleanSession,
|
||||
keepAlive.value);
|
||||
return new Result<MqttConnectVariableHeader>(mqttConnectVariableHeader, numberOfBytesConsumed);
|
||||
}
|
||||
|
||||
private static Result<MqttConnAckVariableHeader> decodeConnAckVariableHeader(ByteBuf buffer) {
|
||||
final boolean sessionPresent = (buffer.readUnsignedByte() & 0x01) == 0x01;
|
||||
byte returnCode = buffer.readByte();
|
||||
final int numberOfBytesConsumed = 2;
|
||||
final MqttConnAckVariableHeader mqttConnAckVariableHeader =
|
||||
new MqttConnAckVariableHeader(MqttConnectReturnCode.valueOf(returnCode), sessionPresent);
|
||||
return new Result<MqttConnAckVariableHeader>(mqttConnAckVariableHeader, numberOfBytesConsumed);
|
||||
}
|
||||
|
||||
private static Result<MqttMessageIdVariableHeader> decodeMessageIdVariableHeader(ByteBuf buffer) {
|
||||
final Result<Integer> messageId = decodeMessageId(buffer);
|
||||
return new Result<MqttMessageIdVariableHeader>(
|
||||
MqttMessageIdVariableHeader.from(messageId.value),
|
||||
messageId.numberOfBytesConsumed);
|
||||
}
|
||||
|
||||
private static Result<MqttPublishVariableHeader> decodePublishVariableHeader(
|
||||
ByteBuf buffer,
|
||||
MqttFixedHeader mqttFixedHeader) {
|
||||
final Result<String> decodedTopic = decodeString(buffer);
|
||||
if (!isValidPublishTopicName(decodedTopic.value)) {
|
||||
throw new DecoderException("invalid publish topic name: " + decodedTopic.value + " (contains wildcards)");
|
||||
}
|
||||
int numberOfBytesConsumed = decodedTopic.numberOfBytesConsumed;
|
||||
|
||||
int messageId = -1;
|
||||
if (mqttFixedHeader.qosLevel().value() > 0) {
|
||||
final Result<Integer> decodedMessageId = decodeMessageId(buffer);
|
||||
messageId = decodedMessageId.value;
|
||||
numberOfBytesConsumed += decodedMessageId.numberOfBytesConsumed;
|
||||
}
|
||||
final MqttPublishVariableHeader mqttPublishVariableHeader =
|
||||
new MqttPublishVariableHeader(decodedTopic.value, messageId);
|
||||
return new Result<MqttPublishVariableHeader>(mqttPublishVariableHeader, numberOfBytesConsumed);
|
||||
}
|
||||
|
||||
private static Result<Integer> decodeMessageId(ByteBuf buffer) {
|
||||
final Result<Integer> messageId = decodeMsbLsb(buffer);
|
||||
if (!isValidMessageId(messageId.value)) {
|
||||
throw new DecoderException("invalid messageId: " + messageId.value);
|
||||
}
|
||||
return messageId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes the payload.
|
||||
*
|
||||
* @param buffer the buffer to decode from
|
||||
* @param messageType type of the message being decoded
|
||||
* @param bytesRemainingInVariablePart bytes remaining
|
||||
* @param variableHeader variable header of the same message
|
||||
* @return the payload
|
||||
*/
|
||||
private static Result<?> decodePayload(
|
||||
ByteBuf buffer,
|
||||
MqttMessageType messageType,
|
||||
int bytesRemainingInVariablePart,
|
||||
Object variableHeader) {
|
||||
switch (messageType) {
|
||||
case CONNECT:
|
||||
return decodeConnectionPayload(buffer, (MqttConnectVariableHeader) variableHeader);
|
||||
|
||||
case SUBSCRIBE:
|
||||
return decodeSubscribePayload(buffer, bytesRemainingInVariablePart);
|
||||
|
||||
case SUBACK:
|
||||
return decodeSubackPayload(buffer, bytesRemainingInVariablePart);
|
||||
|
||||
case UNSUBSCRIBE:
|
||||
return decodeUnsubscribePayload(buffer, bytesRemainingInVariablePart);
|
||||
|
||||
case PUBLISH:
|
||||
return decodePublishPayload(buffer, bytesRemainingInVariablePart);
|
||||
|
||||
default:
|
||||
// unknown payload , no byte consumed
|
||||
return new Result<Object>(null, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private static Result<MqttConnectPayload> decodeConnectionPayload(
|
||||
ByteBuf buffer,
|
||||
MqttConnectVariableHeader mqttConnectVariableHeader) {
|
||||
final Result<String> decodedClientId = decodeString(buffer);
|
||||
final String decodedClientIdValue = decodedClientId.value;
|
||||
final MqttVersion mqttVersion = MqttVersion.fromProtocolNameAndLevel(mqttConnectVariableHeader.name(),
|
||||
(byte) mqttConnectVariableHeader.version());
|
||||
if (!isValidClientId(mqttVersion, decodedClientIdValue)) {
|
||||
throw new MqttIdentifierRejectedException("invalid clientIdentifier: " + decodedClientIdValue);
|
||||
}
|
||||
int numberOfBytesConsumed = decodedClientId.numberOfBytesConsumed;
|
||||
|
||||
Result<String> decodedWillTopic = null;
|
||||
Result<String> decodedWillMessage = null;
|
||||
if (mqttConnectVariableHeader.isWillFlag()) {
|
||||
decodedWillTopic = decodeString(buffer, 0, 32767);
|
||||
numberOfBytesConsumed += decodedWillTopic.numberOfBytesConsumed;
|
||||
decodedWillMessage = decodeAsciiString(buffer);
|
||||
numberOfBytesConsumed += decodedWillMessage.numberOfBytesConsumed;
|
||||
}
|
||||
Result<String> decodedUserName = null;
|
||||
Result<byte[]> decodedPassword = null;
|
||||
if (mqttConnectVariableHeader.hasUserName()) {
|
||||
decodedUserName = decodeString(buffer);
|
||||
numberOfBytesConsumed += decodedUserName.numberOfBytesConsumed;
|
||||
}
|
||||
if (mqttConnectVariableHeader.hasPassword()) {
|
||||
decodedPassword = decodeByte(buffer);
|
||||
numberOfBytesConsumed += decodedPassword.numberOfBytesConsumed;
|
||||
}
|
||||
|
||||
final MqttConnectPayload mqttConnectPayload =
|
||||
new MqttConnectPayload(
|
||||
decodedClientId.value,
|
||||
decodedWillTopic != null ? decodedWillTopic.value : null,
|
||||
decodedWillMessage != null ? decodedWillMessage.value : null,
|
||||
decodedUserName != null ? decodedUserName.value : null,
|
||||
decodedPassword != null ? decodedPassword.value : null);
|
||||
return new Result<MqttConnectPayload>(mqttConnectPayload, numberOfBytesConsumed);
|
||||
}
|
||||
|
||||
private static Result<MqttSubscribePayload> decodeSubscribePayload(
|
||||
ByteBuf buffer,
|
||||
int bytesRemainingInVariablePart) {
|
||||
final List<MqttTopicSubscription> subscribeTopics = new ArrayList<MqttTopicSubscription>();
|
||||
int numberOfBytesConsumed = 0;
|
||||
while (numberOfBytesConsumed < bytesRemainingInVariablePart) {
|
||||
final Result<String> decodedTopicName = decodeString(buffer);
|
||||
numberOfBytesConsumed += decodedTopicName.numberOfBytesConsumed;
|
||||
int qos = buffer.readUnsignedByte() & 0x03;
|
||||
numberOfBytesConsumed++;
|
||||
subscribeTopics.add(new MqttTopicSubscription(decodedTopicName.value, MqttQoS.valueOf(qos)));
|
||||
}
|
||||
return new Result<MqttSubscribePayload>(new MqttSubscribePayload(subscribeTopics), numberOfBytesConsumed);
|
||||
}
|
||||
|
||||
private static Result<MqttSubAckPayload> decodeSubackPayload(
|
||||
ByteBuf buffer,
|
||||
int bytesRemainingInVariablePart) {
|
||||
final List<Integer> grantedQos = new ArrayList<Integer>();
|
||||
int numberOfBytesConsumed = 0;
|
||||
while (numberOfBytesConsumed < bytesRemainingInVariablePart) {
|
||||
int qos = buffer.readUnsignedByte() & 0x03;
|
||||
numberOfBytesConsumed++;
|
||||
grantedQos.add(qos);
|
||||
}
|
||||
return new Result<MqttSubAckPayload>(new MqttSubAckPayload(grantedQos), numberOfBytesConsumed);
|
||||
}
|
||||
|
||||
private static Result<MqttUnsubscribePayload> decodeUnsubscribePayload(
|
||||
ByteBuf buffer,
|
||||
int bytesRemainingInVariablePart) {
|
||||
final List<String> unsubscribeTopics = new ArrayList<String>();
|
||||
int numberOfBytesConsumed = 0;
|
||||
while (numberOfBytesConsumed < bytesRemainingInVariablePart) {
|
||||
final Result<String> decodedTopicName = decodeString(buffer);
|
||||
numberOfBytesConsumed += decodedTopicName.numberOfBytesConsumed;
|
||||
unsubscribeTopics.add(decodedTopicName.value);
|
||||
}
|
||||
return new Result<MqttUnsubscribePayload>(
|
||||
new MqttUnsubscribePayload(unsubscribeTopics),
|
||||
numberOfBytesConsumed);
|
||||
}
|
||||
|
||||
private static Result<ByteBuf> decodePublishPayload(ByteBuf buffer, int bytesRemainingInVariablePart) {
|
||||
ByteBuf b = buffer.readRetainedSlice(bytesRemainingInVariablePart);
|
||||
return new Result<ByteBuf>(b, bytesRemainingInVariablePart);
|
||||
}
|
||||
|
||||
private static Result<String> decodeString(ByteBuf buffer) {
|
||||
return decodeString(buffer, 0, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
private static Result<String> decodeAsciiString(ByteBuf buffer) {
|
||||
Result<String> result = decodeString(buffer, 0, Integer.MAX_VALUE);
|
||||
final String s = result.value;
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
if (s.charAt(i) > 127) {
|
||||
return new Result<String>(null, result.numberOfBytesConsumed);
|
||||
}
|
||||
}
|
||||
return new Result<String>(s, result.numberOfBytesConsumed);
|
||||
}
|
||||
|
||||
private static Result<byte[]> decodeByte(ByteBuf buffer) {
|
||||
return decodeByte(buffer, 0, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
private static Result<String> decodeString(ByteBuf buffer, int minBytes, int maxBytes) {
|
||||
final Result<Integer> decodedSize = decodeMsbLsb(buffer);
|
||||
int size = decodedSize.value;
|
||||
int numberOfBytesConsumed = decodedSize.numberOfBytesConsumed;
|
||||
if (size < minBytes || size > maxBytes) {
|
||||
buffer.skipBytes(size);
|
||||
numberOfBytesConsumed += size;
|
||||
return new Result<String>(null, numberOfBytesConsumed);
|
||||
}
|
||||
String s = buffer.toString(buffer.readerIndex(), size, CharsetUtil.UTF_8);
|
||||
buffer.skipBytes(size);
|
||||
numberOfBytesConsumed += size;
|
||||
return new Result<String>(s, numberOfBytesConsumed);
|
||||
}
|
||||
|
||||
private static Result<byte[]> decodeByte(ByteBuf buffer, int minBytes, int maxBytes) {
|
||||
final Result<Integer> decodedSize = decodeMsbLsb(buffer);
|
||||
int size = decodedSize.value;
|
||||
int numberOfBytesConsumed = decodedSize.numberOfBytesConsumed;
|
||||
if (size < minBytes || size > maxBytes) {
|
||||
buffer.skipBytes(size);
|
||||
numberOfBytesConsumed += size;
|
||||
return new Result<>(null, numberOfBytesConsumed);
|
||||
}
|
||||
byte[] s = new byte[size];
|
||||
buffer.getBytes(buffer.readerIndex(), s, 0, size);
|
||||
buffer.skipBytes(size);
|
||||
numberOfBytesConsumed += size;
|
||||
return new Result<>(s, numberOfBytesConsumed);
|
||||
}
|
||||
|
||||
private static Result<Integer> decodeMsbLsb(ByteBuf buffer) {
|
||||
return decodeMsbLsb(buffer, 0, 65535);
|
||||
}
|
||||
|
||||
private static Result<Integer> decodeMsbLsb(ByteBuf buffer, int min, int max) {
|
||||
short msbSize = buffer.readUnsignedByte();
|
||||
short lsbSize = buffer.readUnsignedByte();
|
||||
final int numberOfBytesConsumed = 2;
|
||||
int result = msbSize << 8 | lsbSize;
|
||||
if (result < min || result > max) {
|
||||
result = -1;
|
||||
}
|
||||
return new Result<Integer>(result, numberOfBytesConsumed);
|
||||
}
|
||||
|
||||
private static final class Result<T> {
|
||||
|
||||
private final T value;
|
||||
private final int numberOfBytesConsumed;
|
||||
|
||||
Result(T value, int numberOfBytesConsumed) {
|
||||
this.value = value;
|
||||
this.numberOfBytesConsumed = numberOfBytesConsumed;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,410 @@
|
||||
/*
|
||||
* Copyright 2014 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you 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 io.netty.handler.codec.mqtt;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToMessageEncoder;
|
||||
import io.netty.util.CharsetUtil;
|
||||
import io.netty.util.internal.EmptyArrays;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static io.netty.handler.codec.mqtt.MqttCodecUtil.*;
|
||||
|
||||
/**
|
||||
* Encodes Mqtt messages into bytes following the protocol specification v3.1
|
||||
* as described here <a href="http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html">MQTTV3.1</a>
|
||||
*/
|
||||
@ChannelHandler.Sharable
|
||||
public final class MqttEncoder extends MessageToMessageEncoder<MqttMessage> {
|
||||
|
||||
public static final MqttEncoder INSTANCE = new MqttEncoder();
|
||||
|
||||
private MqttEncoder() { }
|
||||
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, MqttMessage msg, List<Object> out) throws Exception {
|
||||
out.add(doEncode(ctx.alloc(), msg));
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the main encoding method.
|
||||
* It's only visible for testing.
|
||||
*
|
||||
* @param byteBufAllocator Allocates ByteBuf
|
||||
* @param message MQTT message to encode
|
||||
* @return ByteBuf with encoded bytes
|
||||
*/
|
||||
static ByteBuf doEncode(ByteBufAllocator byteBufAllocator, MqttMessage message) {
|
||||
|
||||
switch (message.fixedHeader().messageType()) {
|
||||
case CONNECT:
|
||||
return encodeConnectMessage(byteBufAllocator, (MqttConnectMessage) message);
|
||||
|
||||
case CONNACK:
|
||||
return encodeConnAckMessage(byteBufAllocator, (MqttConnAckMessage) message);
|
||||
|
||||
case PUBLISH:
|
||||
return encodePublishMessage(byteBufAllocator, (MqttPublishMessage) message);
|
||||
|
||||
case SUBSCRIBE:
|
||||
return encodeSubscribeMessage(byteBufAllocator, (MqttSubscribeMessage) message);
|
||||
|
||||
case UNSUBSCRIBE:
|
||||
return encodeUnsubscribeMessage(byteBufAllocator, (MqttUnsubscribeMessage) message);
|
||||
|
||||
case SUBACK:
|
||||
return encodeSubAckMessage(byteBufAllocator, (MqttSubAckMessage) message);
|
||||
|
||||
case UNSUBACK:
|
||||
case PUBACK:
|
||||
case PUBREC:
|
||||
case PUBREL:
|
||||
case PUBCOMP:
|
||||
return encodeMessageWithOnlySingleByteFixedHeaderAndMessageId(byteBufAllocator, message);
|
||||
|
||||
case PINGREQ:
|
||||
case PINGRESP:
|
||||
case DISCONNECT:
|
||||
return encodeMessageWithOnlySingleByteFixedHeader(byteBufAllocator, message);
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException(
|
||||
"Unknown message type: " + message.fixedHeader().messageType().value());
|
||||
}
|
||||
}
|
||||
|
||||
private static ByteBuf encodeConnectMessage(
|
||||
ByteBufAllocator byteBufAllocator,
|
||||
MqttConnectMessage message) {
|
||||
int payloadBufferSize = 0;
|
||||
|
||||
MqttFixedHeader mqttFixedHeader = message.fixedHeader();
|
||||
MqttConnectVariableHeader variableHeader = message.variableHeader();
|
||||
MqttConnectPayload payload = message.payload();
|
||||
MqttVersion mqttVersion = MqttVersion.fromProtocolNameAndLevel(variableHeader.name(),
|
||||
(byte) variableHeader.version());
|
||||
|
||||
// Client id
|
||||
String clientIdentifier = payload.clientIdentifier();
|
||||
if (!isValidClientId(mqttVersion, clientIdentifier)) {
|
||||
throw new MqttIdentifierRejectedException("invalid clientIdentifier: " + clientIdentifier);
|
||||
}
|
||||
byte[] clientIdentifierBytes = encodeStringUtf8(clientIdentifier);
|
||||
payloadBufferSize += 2 + clientIdentifierBytes.length;
|
||||
|
||||
// Will topic and message
|
||||
String willTopic = payload.willTopic();
|
||||
byte[] willTopicBytes = willTopic != null ? encodeStringUtf8(willTopic) : EmptyArrays.EMPTY_BYTES;
|
||||
String willMessage = payload.willMessage();
|
||||
byte[] willMessageBytes = willMessage != null ? encodeStringUtf8(willMessage) : EmptyArrays.EMPTY_BYTES;
|
||||
if (variableHeader.isWillFlag()) {
|
||||
payloadBufferSize += 2 + willTopicBytes.length;
|
||||
payloadBufferSize += 2 + willMessageBytes.length;
|
||||
}
|
||||
|
||||
String userName = payload.userName();
|
||||
byte[] userNameBytes = userName != null ? encodeStringUtf8(userName) : EmptyArrays.EMPTY_BYTES;
|
||||
if (variableHeader.hasUserName()) {
|
||||
payloadBufferSize += 2 + userNameBytes.length;
|
||||
}
|
||||
|
||||
byte[] passwordBytes = payload.password();
|
||||
if (variableHeader.hasPassword()) {
|
||||
payloadBufferSize += 2 + passwordBytes.length;
|
||||
}
|
||||
|
||||
// Fixed header
|
||||
byte[] protocolNameBytes = mqttVersion.protocolNameBytes();
|
||||
int variableHeaderBufferSize = 2 + protocolNameBytes.length + 4;
|
||||
int variablePartSize = variableHeaderBufferSize + payloadBufferSize;
|
||||
int fixedHeaderBufferSize = 1 + getVariableLengthInt(variablePartSize);
|
||||
ByteBuf buf = byteBufAllocator.buffer(fixedHeaderBufferSize + variablePartSize);
|
||||
buf.writeByte(getFixedHeaderByte1(mqttFixedHeader));
|
||||
writeVariableLengthInt(buf, variablePartSize);
|
||||
|
||||
buf.writeShort(protocolNameBytes.length);
|
||||
buf.writeBytes(protocolNameBytes);
|
||||
|
||||
buf.writeByte(variableHeader.version());
|
||||
buf.writeByte(getConnVariableHeaderFlag(variableHeader));
|
||||
buf.writeShort(variableHeader.keepAliveTimeSeconds());
|
||||
|
||||
// Payload
|
||||
buf.writeShort(clientIdentifierBytes.length);
|
||||
buf.writeBytes(clientIdentifierBytes, 0, clientIdentifierBytes.length);
|
||||
if (variableHeader.isWillFlag()) {
|
||||
buf.writeShort(willTopicBytes.length);
|
||||
buf.writeBytes(willTopicBytes, 0, willTopicBytes.length);
|
||||
buf.writeShort(willMessageBytes.length);
|
||||
buf.writeBytes(willMessageBytes, 0, willMessageBytes.length);
|
||||
}
|
||||
if (variableHeader.hasUserName()) {
|
||||
buf.writeShort(userNameBytes.length);
|
||||
buf.writeBytes(userNameBytes, 0, userNameBytes.length);
|
||||
}
|
||||
if (variableHeader.hasPassword()) {
|
||||
buf.writeShort(passwordBytes.length);
|
||||
buf.writeBytes(passwordBytes, 0, passwordBytes.length);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
private static int getConnVariableHeaderFlag(MqttConnectVariableHeader variableHeader) {
|
||||
int flagByte = 0;
|
||||
if (variableHeader.hasUserName()) {
|
||||
flagByte |= 0x80;
|
||||
}
|
||||
if (variableHeader.hasPassword()) {
|
||||
flagByte |= 0x40;
|
||||
}
|
||||
if (variableHeader.isWillRetain()) {
|
||||
flagByte |= 0x20;
|
||||
}
|
||||
flagByte |= (variableHeader.willQos() & 0x03) << 3;
|
||||
if (variableHeader.isWillFlag()) {
|
||||
flagByte |= 0x04;
|
||||
}
|
||||
if (variableHeader.isCleanSession()) {
|
||||
flagByte |= 0x02;
|
||||
}
|
||||
return flagByte;
|
||||
}
|
||||
|
||||
private static ByteBuf encodeConnAckMessage(
|
||||
ByteBufAllocator byteBufAllocator,
|
||||
MqttConnAckMessage message) {
|
||||
int length = 4;
|
||||
MqttConnectAckPayload payload = null;
|
||||
if (message.payload() != null) {
|
||||
payload = (MqttConnectAckPayload)message.payload();
|
||||
if (payload.getData() != null && payload.getData().length > 0) {
|
||||
length += payload.getData().length;
|
||||
}
|
||||
}
|
||||
ByteBuf buf = byteBufAllocator.buffer(length);
|
||||
buf.writeByte(getFixedHeaderByte1(message.fixedHeader()));
|
||||
buf.writeByte(length - 2);
|
||||
buf.writeByte(message.variableHeader().isSessionPresent() ? 0x01 : 0x00);
|
||||
buf.writeByte(message.variableHeader().connectReturnCode().byteValue());
|
||||
if (length > 4) {
|
||||
buf.writeBytes(payload.getData());
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
private static ByteBuf encodeSubscribeMessage(
|
||||
ByteBufAllocator byteBufAllocator,
|
||||
MqttSubscribeMessage message) {
|
||||
int variableHeaderBufferSize = 2;
|
||||
int payloadBufferSize = 0;
|
||||
|
||||
MqttFixedHeader mqttFixedHeader = message.fixedHeader();
|
||||
MqttMessageIdVariableHeader variableHeader = message.variableHeader();
|
||||
MqttSubscribePayload payload = message.payload();
|
||||
|
||||
for (MqttTopicSubscription topic : payload.topicSubscriptions()) {
|
||||
String topicName = topic.topicName();
|
||||
byte[] topicNameBytes = encodeStringUtf8(topicName);
|
||||
payloadBufferSize += 2 + topicNameBytes.length;
|
||||
payloadBufferSize += 1;
|
||||
}
|
||||
|
||||
int variablePartSize = variableHeaderBufferSize + payloadBufferSize;
|
||||
int fixedHeaderBufferSize = 1 + getVariableLengthInt(variablePartSize);
|
||||
|
||||
ByteBuf buf = byteBufAllocator.buffer(fixedHeaderBufferSize + variablePartSize);
|
||||
buf.writeByte(getFixedHeaderByte1(mqttFixedHeader));
|
||||
writeVariableLengthInt(buf, variablePartSize);
|
||||
|
||||
// Variable Header
|
||||
int messageId = variableHeader.messageId();
|
||||
buf.writeShort(messageId);
|
||||
|
||||
// Payload
|
||||
for (MqttTopicSubscription topic : payload.topicSubscriptions()) {
|
||||
String topicName = topic.topicName();
|
||||
byte[] topicNameBytes = encodeStringUtf8(topicName);
|
||||
buf.writeShort(topicNameBytes.length);
|
||||
buf.writeBytes(topicNameBytes, 0, topicNameBytes.length);
|
||||
buf.writeByte(topic.qualityOfService().value());
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
private static ByteBuf encodeUnsubscribeMessage(
|
||||
ByteBufAllocator byteBufAllocator,
|
||||
MqttUnsubscribeMessage message) {
|
||||
int variableHeaderBufferSize = 2;
|
||||
int payloadBufferSize = 0;
|
||||
|
||||
MqttFixedHeader mqttFixedHeader = message.fixedHeader();
|
||||
MqttMessageIdVariableHeader variableHeader = message.variableHeader();
|
||||
MqttUnsubscribePayload payload = message.payload();
|
||||
|
||||
for (String topicName : payload.topics()) {
|
||||
byte[] topicNameBytes = encodeStringUtf8(topicName);
|
||||
payloadBufferSize += 2 + topicNameBytes.length;
|
||||
}
|
||||
|
||||
int variablePartSize = variableHeaderBufferSize + payloadBufferSize;
|
||||
int fixedHeaderBufferSize = 1 + getVariableLengthInt(variablePartSize);
|
||||
|
||||
ByteBuf buf = byteBufAllocator.buffer(fixedHeaderBufferSize + variablePartSize);
|
||||
buf.writeByte(getFixedHeaderByte1(mqttFixedHeader));
|
||||
writeVariableLengthInt(buf, variablePartSize);
|
||||
|
||||
// Variable Header
|
||||
int messageId = variableHeader.messageId();
|
||||
buf.writeShort(messageId);
|
||||
|
||||
// Payload
|
||||
for (String topicName : payload.topics()) {
|
||||
byte[] topicNameBytes = encodeStringUtf8(topicName);
|
||||
buf.writeShort(topicNameBytes.length);
|
||||
buf.writeBytes(topicNameBytes, 0, topicNameBytes.length);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
private static ByteBuf encodeSubAckMessage(
|
||||
ByteBufAllocator byteBufAllocator,
|
||||
MqttSubAckMessage message) {
|
||||
int variableHeaderBufferSize = 2;
|
||||
int payloadBufferSize = message.payload().grantedQoSLevels().size();
|
||||
int variablePartSize = variableHeaderBufferSize + payloadBufferSize;
|
||||
int fixedHeaderBufferSize = 1 + getVariableLengthInt(variablePartSize);
|
||||
ByteBuf buf = byteBufAllocator.buffer(fixedHeaderBufferSize + variablePartSize);
|
||||
buf.writeByte(getFixedHeaderByte1(message.fixedHeader()));
|
||||
writeVariableLengthInt(buf, variablePartSize);
|
||||
buf.writeShort(message.variableHeader().messageId());
|
||||
for (int qos : message.payload().grantedQoSLevels()) {
|
||||
buf.writeByte(qos);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
private static ByteBuf encodePublishMessage(
|
||||
ByteBufAllocator byteBufAllocator,
|
||||
MqttPublishMessage message) {
|
||||
MqttFixedHeader mqttFixedHeader = message.fixedHeader();
|
||||
MqttPublishVariableHeader variableHeader = message.variableHeader();
|
||||
ByteBuf payload = message.payload().duplicate();
|
||||
|
||||
String topicName = variableHeader.topicName();
|
||||
byte[] topicNameBytes = encodeStringUtf8(topicName);
|
||||
|
||||
int variableHeaderBufferSize = 2 + topicNameBytes.length +
|
||||
(mqttFixedHeader.qosLevel().value() > 0 ? 2 : 0);
|
||||
int payloadBufferSize = payload.readableBytes();
|
||||
int variablePartSize = variableHeaderBufferSize + payloadBufferSize;
|
||||
int fixedHeaderBufferSize = 1 + getVariableLengthInt(variablePartSize);
|
||||
|
||||
ByteBuf buf = byteBufAllocator.buffer(fixedHeaderBufferSize + variablePartSize);
|
||||
buf.writeByte(getFixedHeaderByte1(mqttFixedHeader));
|
||||
writeVariableLengthInt(buf, variablePartSize);
|
||||
buf.writeShort(topicNameBytes.length);
|
||||
buf.writeBytes(topicNameBytes);
|
||||
if (mqttFixedHeader.qosLevel().value() > 0) {
|
||||
buf.writeShort(variableHeader.messageId());
|
||||
}
|
||||
buf.writeBytes(payload);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
private static ByteBuf encodeMessageWithOnlySingleByteFixedHeaderAndMessageId(
|
||||
ByteBufAllocator byteBufAllocator,
|
||||
MqttMessage message) {
|
||||
MqttFixedHeader mqttFixedHeader = message.fixedHeader();
|
||||
MqttMessageIdVariableHeader variableHeader = (MqttMessageIdVariableHeader) message.variableHeader();
|
||||
int msgId = variableHeader.messageId();
|
||||
|
||||
int variableHeaderBufferSize = 2; // variable part only has a message id
|
||||
|
||||
ByteBuf payload = null;
|
||||
if (message.payload() != null) {
|
||||
payload = ((ByteBuf)message.payload()).duplicate();
|
||||
variableHeaderBufferSize += payload.readableBytes();
|
||||
}
|
||||
int fixedHeaderBufferSize = 1 + getVariableLengthInt(variableHeaderBufferSize);
|
||||
ByteBuf buf = byteBufAllocator.buffer(fixedHeaderBufferSize + variableHeaderBufferSize);
|
||||
buf.writeByte(getFixedHeaderByte1(mqttFixedHeader));
|
||||
writeVariableLengthInt(buf, variableHeaderBufferSize);
|
||||
buf.writeShort(msgId);
|
||||
if (payload != null) {
|
||||
buf.writeBytes(payload);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
private static ByteBuf encodeMessageWithOnlySingleByteFixedHeader(
|
||||
ByteBufAllocator byteBufAllocator,
|
||||
MqttMessage message) {
|
||||
MqttFixedHeader mqttFixedHeader = message.fixedHeader();
|
||||
ByteBuf buf = byteBufAllocator.buffer(2);
|
||||
buf.writeByte(getFixedHeaderByte1(mqttFixedHeader));
|
||||
buf.writeByte(0);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
private static int getFixedHeaderByte1(MqttFixedHeader header) {
|
||||
int ret = 0;
|
||||
ret |= header.messageType().value() << 4;
|
||||
if (header.isDup()) {
|
||||
ret |= 0x08;
|
||||
}
|
||||
ret |= header.qosLevel().value() << 1;
|
||||
if (header.isRetain()) {
|
||||
ret |= 0x01;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static void writeVariableLengthInt(ByteBuf buf, int num) {
|
||||
do {
|
||||
int digit = num % 128;
|
||||
num /= 128;
|
||||
if (num > 0) {
|
||||
digit |= 0x80;
|
||||
}
|
||||
buf.writeByte(digit);
|
||||
} while (num > 0);
|
||||
}
|
||||
|
||||
private static int getVariableLengthInt(int num) {
|
||||
int count = 0;
|
||||
do {
|
||||
num /= 128;
|
||||
count++;
|
||||
} while (num > 0);
|
||||
return count;
|
||||
}
|
||||
|
||||
private static byte[] encodeStringUtf8(String s) {
|
||||
return s.getBytes(CharsetUtil.UTF_8);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2014 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you 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 io.netty.handler.codec.mqtt;
|
||||
|
||||
import io.netty.util.internal.ObjectUtil;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
/**
|
||||
* See <a href="http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#fixed-header">
|
||||
* MQTTV3.1/fixed-header</a>
|
||||
*/
|
||||
public final class MqttFixedHeader {
|
||||
|
||||
private final MqttMessageType messageType;
|
||||
private final boolean isDup;
|
||||
private final MqttQoS qosLevel;
|
||||
private final boolean isRetain;
|
||||
private final int remainingLength;
|
||||
|
||||
public MqttFixedHeader(
|
||||
MqttMessageType messageType,
|
||||
boolean isDup,
|
||||
MqttQoS qosLevel,
|
||||
boolean isRetain,
|
||||
int remainingLength) {
|
||||
this.messageType = ObjectUtil.checkNotNull(messageType, "messageType");
|
||||
this.isDup = isDup;
|
||||
this.qosLevel = ObjectUtil.checkNotNull(qosLevel, "qosLevel");
|
||||
this.isRetain = isRetain;
|
||||
this.remainingLength = remainingLength;
|
||||
}
|
||||
|
||||
public MqttMessageType messageType() {
|
||||
return messageType;
|
||||
}
|
||||
|
||||
public boolean isDup() {
|
||||
return isDup;
|
||||
}
|
||||
|
||||
public MqttQoS qosLevel() {
|
||||
return qosLevel;
|
||||
}
|
||||
|
||||
public boolean isRetain() {
|
||||
return isRetain;
|
||||
}
|
||||
|
||||
public int remainingLength() {
|
||||
return remainingLength;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder(StringUtil.simpleClassName(this))
|
||||
.append('[')
|
||||
.append("messageType=").append(messageType)
|
||||
.append(", isDup=").append(isDup)
|
||||
.append(", qosLevel=").append(qosLevel)
|
||||
.append(", isRetain=").append(isRetain)
|
||||
.append(", remainingLength=").append(remainingLength)
|
||||
.append(']')
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2014 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you 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 io.netty.handler.codec.mqtt;
|
||||
|
||||
import io.netty.handler.codec.DecoderException;
|
||||
|
||||
/**
|
||||
* A {@link MqttIdentifierRejectedException} which is thrown when a CONNECT request contains invalid client identifier.
|
||||
*/
|
||||
public final class MqttIdentifierRejectedException extends DecoderException {
|
||||
|
||||
private static final long serialVersionUID = -1323503322689614981L;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*/
|
||||
public MqttIdentifierRejectedException() { }
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*/
|
||||
public MqttIdentifierRejectedException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*/
|
||||
public MqttIdentifierRejectedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*/
|
||||
public MqttIdentifierRejectedException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2014 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you 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 io.netty.handler.codec.mqtt;
|
||||
|
||||
import io.netty.handler.codec.DecoderResult;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
/**
|
||||
* Base class for all MQTT message types.
|
||||
*/
|
||||
public class MqttMessage {
|
||||
|
||||
private final MqttFixedHeader mqttFixedHeader;
|
||||
private final Object variableHeader;
|
||||
private final Object payload;
|
||||
private final DecoderResult decoderResult;
|
||||
|
||||
public MqttMessage(MqttFixedHeader mqttFixedHeader) {
|
||||
this(mqttFixedHeader, null, null);
|
||||
}
|
||||
|
||||
public MqttMessage(MqttFixedHeader mqttFixedHeader, Object variableHeader) {
|
||||
this(mqttFixedHeader, variableHeader, null);
|
||||
}
|
||||
|
||||
public MqttMessage(MqttFixedHeader mqttFixedHeader, Object variableHeader, Object payload) {
|
||||
this(mqttFixedHeader, variableHeader, payload, DecoderResult.SUCCESS);
|
||||
}
|
||||
|
||||
public MqttMessage(
|
||||
MqttFixedHeader mqttFixedHeader,
|
||||
Object variableHeader,
|
||||
Object payload,
|
||||
DecoderResult decoderResult) {
|
||||
this.mqttFixedHeader = mqttFixedHeader;
|
||||
this.variableHeader = variableHeader;
|
||||
this.payload = payload;
|
||||
this.decoderResult = decoderResult;
|
||||
}
|
||||
|
||||
public MqttFixedHeader fixedHeader() {
|
||||
return mqttFixedHeader;
|
||||
}
|
||||
|
||||
public Object variableHeader() {
|
||||
return variableHeader;
|
||||
}
|
||||
|
||||
public Object payload() {
|
||||
return payload;
|
||||
}
|
||||
|
||||
public DecoderResult decoderResult() {
|
||||
return decoderResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder(StringUtil.simpleClassName(this))
|
||||
.append('[')
|
||||
.append("fixedHeader=").append(fixedHeader() != null ? fixedHeader().toString() : "")
|
||||
.append(", variableHeader=").append(variableHeader() != null ? variableHeader.toString() : "")
|
||||
.append(", payload=").append(payload() != null ? payload.toString() : "")
|
||||
.append(']')
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
* Copyright 2017 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you 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 io.netty.handler.codec.mqtt;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public final class MqttMessageBuilders {
|
||||
|
||||
public static final class PublishBuilder {
|
||||
private String topic;
|
||||
private boolean retained;
|
||||
private MqttQoS qos;
|
||||
private ByteBuf payload;
|
||||
private int messageId;
|
||||
|
||||
PublishBuilder() {
|
||||
}
|
||||
|
||||
public PublishBuilder topicName(String topic) {
|
||||
this.topic = topic;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PublishBuilder retained(boolean retained) {
|
||||
this.retained = retained;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PublishBuilder qos(MqttQoS qos) {
|
||||
this.qos = qos;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PublishBuilder payload(ByteBuf payload) {
|
||||
this.payload = payload;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PublishBuilder messageId(int messageId) {
|
||||
this.messageId = messageId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MqttPublishMessage build() {
|
||||
MqttFixedHeader mqttFixedHeader = new MqttFixedHeader(MqttMessageType.PUBLISH, false, qos, retained, 0);
|
||||
MqttPublishVariableHeader mqttVariableHeader = new MqttPublishVariableHeader(topic, messageId);
|
||||
return new MqttPublishMessage(mqttFixedHeader, mqttVariableHeader, Unpooled.buffer().writeBytes(payload));
|
||||
}
|
||||
}
|
||||
|
||||
public static final class ConnectBuilder {
|
||||
|
||||
private MqttVersion version = MqttVersion.MQTT_3_1_1;
|
||||
private String clientId;
|
||||
private boolean cleanSession;
|
||||
private boolean hasUser;
|
||||
private boolean hasPassword;
|
||||
private int keepAliveSecs;
|
||||
private boolean willFlag;
|
||||
private boolean willRetain;
|
||||
private MqttQoS willQos = MqttQoS.AT_MOST_ONCE;
|
||||
private String willTopic;
|
||||
private String willMessage;
|
||||
private String username;
|
||||
private byte[] password;
|
||||
|
||||
ConnectBuilder() {
|
||||
}
|
||||
|
||||
public ConnectBuilder protocolVersion(MqttVersion version) {
|
||||
this.version = version;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConnectBuilder clientId(String clientId) {
|
||||
this.clientId = clientId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConnectBuilder cleanSession(boolean cleanSession) {
|
||||
this.cleanSession = cleanSession;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConnectBuilder keepAlive(int keepAliveSecs) {
|
||||
this.keepAliveSecs = keepAliveSecs;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConnectBuilder willFlag(boolean willFlag) {
|
||||
this.willFlag = willFlag;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConnectBuilder willQoS(MqttQoS willQos) {
|
||||
this.willQos = willQos;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConnectBuilder willTopic(String willTopic) {
|
||||
this.willTopic = willTopic;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConnectBuilder willMessage(String willMessage) {
|
||||
this.willMessage = willMessage;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConnectBuilder willRetain(boolean willRetain) {
|
||||
this.willRetain = willRetain;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConnectBuilder hasUser(boolean value) {
|
||||
this.hasUser = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConnectBuilder hasPassword(boolean value) {
|
||||
this.hasPassword = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConnectBuilder username(String username) {
|
||||
this.hasUser = true;
|
||||
this.username = username;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConnectBuilder password(byte[] password) {
|
||||
this.hasPassword = true;
|
||||
this.password = password;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MqttConnectMessage build() {
|
||||
MqttFixedHeader mqttFixedHeader =
|
||||
new MqttFixedHeader(MqttMessageType.CONNECT, false, MqttQoS.AT_MOST_ONCE, false, 0);
|
||||
MqttConnectVariableHeader mqttConnectVariableHeader =
|
||||
new MqttConnectVariableHeader(
|
||||
version.protocolName(),
|
||||
version.protocolLevel(),
|
||||
hasUser,
|
||||
hasPassword,
|
||||
willRetain,
|
||||
willQos.value(),
|
||||
willFlag,
|
||||
cleanSession,
|
||||
keepAliveSecs);
|
||||
MqttConnectPayload mqttConnectPayload =
|
||||
new MqttConnectPayload(clientId, willTopic, willMessage, username, password);
|
||||
return new MqttConnectMessage(mqttFixedHeader, mqttConnectVariableHeader, mqttConnectPayload);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class SubscribeBuilder {
|
||||
|
||||
private List<MqttTopicSubscription> subscriptions;
|
||||
private int messageId;
|
||||
|
||||
SubscribeBuilder() {
|
||||
}
|
||||
|
||||
public SubscribeBuilder addSubscription(MqttQoS qos, String topic) {
|
||||
if (subscriptions == null) {
|
||||
subscriptions = new ArrayList<MqttTopicSubscription>(5);
|
||||
}
|
||||
subscriptions.add(new MqttTopicSubscription(topic, qos));
|
||||
return this;
|
||||
}
|
||||
|
||||
public SubscribeBuilder messageId(int messageId) {
|
||||
this.messageId = messageId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MqttSubscribeMessage build() {
|
||||
MqttFixedHeader mqttFixedHeader =
|
||||
new MqttFixedHeader(MqttMessageType.SUBSCRIBE, false, MqttQoS.AT_LEAST_ONCE, false, 0);
|
||||
MqttMessageIdVariableHeader mqttVariableHeader = MqttMessageIdVariableHeader.from(messageId);
|
||||
MqttSubscribePayload mqttSubscribePayload = new MqttSubscribePayload(subscriptions);
|
||||
return new MqttSubscribeMessage(mqttFixedHeader, mqttVariableHeader, mqttSubscribePayload);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class UnsubscribeBuilder {
|
||||
|
||||
private List<String> topicFilters;
|
||||
private int messageId;
|
||||
|
||||
UnsubscribeBuilder() {
|
||||
}
|
||||
|
||||
public UnsubscribeBuilder addTopicFilter(String topic) {
|
||||
if (topicFilters == null) {
|
||||
topicFilters = new ArrayList<String>(5);
|
||||
}
|
||||
topicFilters.add(topic);
|
||||
return this;
|
||||
}
|
||||
|
||||
public UnsubscribeBuilder messageId(int messageId) {
|
||||
this.messageId = messageId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MqttUnsubscribeMessage build() {
|
||||
MqttFixedHeader mqttFixedHeader =
|
||||
new MqttFixedHeader(MqttMessageType.UNSUBSCRIBE, false, MqttQoS.AT_LEAST_ONCE, false, 0);
|
||||
MqttMessageIdVariableHeader mqttVariableHeader = MqttMessageIdVariableHeader.from(messageId);
|
||||
MqttUnsubscribePayload mqttSubscribePayload = new MqttUnsubscribePayload(topicFilters);
|
||||
return new MqttUnsubscribeMessage(mqttFixedHeader, mqttVariableHeader, mqttSubscribePayload);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class ConnAckBuilder {
|
||||
|
||||
private MqttConnectReturnCode returnCode;
|
||||
private boolean sessionPresent;
|
||||
|
||||
ConnAckBuilder() {
|
||||
}
|
||||
|
||||
public ConnAckBuilder returnCode(MqttConnectReturnCode returnCode) {
|
||||
this.returnCode = returnCode;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConnAckBuilder sessionPresent(boolean sessionPresent) {
|
||||
this.sessionPresent = sessionPresent;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MqttConnAckMessage build() {
|
||||
MqttFixedHeader mqttFixedHeader =
|
||||
new MqttFixedHeader(MqttMessageType.CONNACK, false, MqttQoS.AT_MOST_ONCE, false, 0);
|
||||
MqttConnAckVariableHeader mqttConnAckVariableHeader =
|
||||
new MqttConnAckVariableHeader(returnCode, sessionPresent);
|
||||
return new MqttConnAckMessage(mqttFixedHeader, mqttConnAckVariableHeader);
|
||||
}
|
||||
}
|
||||
|
||||
public static ConnectBuilder connect() {
|
||||
return new ConnectBuilder();
|
||||
}
|
||||
|
||||
public static ConnAckBuilder connAck() {
|
||||
return new ConnAckBuilder();
|
||||
}
|
||||
|
||||
public static PublishBuilder publish() {
|
||||
return new PublishBuilder();
|
||||
}
|
||||
|
||||
public static SubscribeBuilder subscribe() {
|
||||
return new SubscribeBuilder();
|
||||
}
|
||||
|
||||
public static UnsubscribeBuilder unsubscribe() {
|
||||
return new UnsubscribeBuilder();
|
||||
}
|
||||
|
||||
private MqttMessageBuilders() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2014 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you 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 io.netty.handler.codec.mqtt;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.handler.codec.DecoderResult;
|
||||
|
||||
/**
|
||||
* Utility class with factory methods to create different types of MQTT messages.
|
||||
*/
|
||||
public final class MqttMessageFactory {
|
||||
|
||||
public static MqttMessage newMessage(MqttFixedHeader mqttFixedHeader, Object variableHeader, Object payload) {
|
||||
switch (mqttFixedHeader.messageType()) {
|
||||
case CONNECT :
|
||||
return new MqttConnectMessage(
|
||||
mqttFixedHeader,
|
||||
(MqttConnectVariableHeader) variableHeader,
|
||||
(MqttConnectPayload) payload);
|
||||
|
||||
case CONNACK:
|
||||
return new MqttConnAckMessage(mqttFixedHeader, (MqttConnAckVariableHeader) variableHeader);
|
||||
|
||||
case SUBSCRIBE:
|
||||
return new MqttSubscribeMessage(
|
||||
mqttFixedHeader,
|
||||
(MqttMessageIdVariableHeader) variableHeader,
|
||||
(MqttSubscribePayload) payload);
|
||||
|
||||
case SUBACK:
|
||||
return new MqttSubAckMessage(
|
||||
mqttFixedHeader,
|
||||
(MqttMessageIdVariableHeader) variableHeader,
|
||||
(MqttSubAckPayload) payload);
|
||||
|
||||
case UNSUBACK:
|
||||
return new MqttUnsubAckMessage(
|
||||
mqttFixedHeader,
|
||||
(MqttMessageIdVariableHeader) variableHeader);
|
||||
|
||||
case UNSUBSCRIBE:
|
||||
return new MqttUnsubscribeMessage(
|
||||
mqttFixedHeader,
|
||||
(MqttMessageIdVariableHeader) variableHeader,
|
||||
(MqttUnsubscribePayload) payload);
|
||||
|
||||
case PUBLISH:
|
||||
return new MqttPublishMessage(
|
||||
mqttFixedHeader,
|
||||
(MqttPublishVariableHeader) variableHeader,
|
||||
(ByteBuf) payload);
|
||||
|
||||
case PUBACK:
|
||||
return new MqttPubAckMessage(mqttFixedHeader, (MqttMessageIdVariableHeader) variableHeader);
|
||||
case PUBREC:
|
||||
case PUBREL:
|
||||
case PUBCOMP:
|
||||
return new MqttMessage(mqttFixedHeader, variableHeader);
|
||||
|
||||
case PINGREQ:
|
||||
case PINGRESP:
|
||||
case DISCONNECT:
|
||||
return new MqttMessage(mqttFixedHeader);
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException("unknown message type: " + mqttFixedHeader.messageType());
|
||||
}
|
||||
}
|
||||
|
||||
public static MqttMessage newInvalidMessage(Throwable cause) {
|
||||
return new MqttMessage(null, null, null, DecoderResult.failure(cause));
|
||||
}
|
||||
|
||||
private MqttMessageFactory() { }
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2014 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you 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 io.netty.handler.codec.mqtt;
|
||||
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
/**
|
||||
* Variable Header containing only Message Id
|
||||
* See <a href="http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#msg-id">MQTTV3.1/msg-id</a>
|
||||
*/
|
||||
public final class MqttMessageIdVariableHeader {
|
||||
|
||||
private final int messageId;
|
||||
|
||||
public static MqttMessageIdVariableHeader from(int messageId) {
|
||||
if (messageId < 1 || messageId > 0xffff) {
|
||||
throw new IllegalArgumentException("messageId: " + messageId + " (expected: 1 ~ 65535)");
|
||||
}
|
||||
return new MqttMessageIdVariableHeader(messageId);
|
||||
}
|
||||
|
||||
private MqttMessageIdVariableHeader(int messageId) {
|
||||
this.messageId = messageId;
|
||||
}
|
||||
|
||||
public int messageId() {
|
||||
return messageId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder(StringUtil.simpleClassName(this))
|
||||
.append('[')
|
||||
.append("messageId=").append(messageId)
|
||||
.append(']')
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2014 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you 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 io.netty.handler.codec.mqtt;
|
||||
|
||||
/**
|
||||
* MQTT Message Types.
|
||||
*/
|
||||
public enum MqttMessageType {
|
||||
CONNECT(1),
|
||||
CONNACK(2),
|
||||
PUBLISH(3),
|
||||
PUBACK(4),
|
||||
PUBREC(5),
|
||||
PUBREL(6),
|
||||
PUBCOMP(7),
|
||||
SUBSCRIBE(8),
|
||||
SUBACK(9),
|
||||
UNSUBSCRIBE(10),
|
||||
UNSUBACK(11),
|
||||
PINGREQ(12),
|
||||
PINGRESP(13),
|
||||
DISCONNECT(14);
|
||||
|
||||
private final int value;
|
||||
|
||||
MqttMessageType(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int value() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static MqttMessageType valueOf(int type) {
|
||||
for (MqttMessageType t : values()) {
|
||||
if (t.value == type) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("unknown message type: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2014 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you 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 io.netty.handler.codec.mqtt;
|
||||
|
||||
/**
|
||||
* See <a href="http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#puback">MQTTV3.1/puback</a>
|
||||
*/
|
||||
public final class MqttPubAckMessage extends MqttMessage {
|
||||
|
||||
public MqttPubAckMessage(MqttFixedHeader mqttFixedHeader, MqttMessageIdVariableHeader variableHeader) {
|
||||
super(mqttFixedHeader, variableHeader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MqttMessageIdVariableHeader variableHeader() {
|
||||
return (MqttMessageIdVariableHeader) super.variableHeader();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright 2014 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you 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 io.netty.handler.codec.mqtt;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufHolder;
|
||||
import io.netty.util.IllegalReferenceCountException;
|
||||
|
||||
/**
|
||||
* See <a href="http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#publish">MQTTV3.1/publish</a>
|
||||
*/
|
||||
public class MqttPublishMessage extends MqttMessage implements ByteBufHolder {
|
||||
|
||||
public MqttPublishMessage(
|
||||
MqttFixedHeader mqttFixedHeader,
|
||||
MqttPublishVariableHeader variableHeader,
|
||||
ByteBuf payload) {
|
||||
super(mqttFixedHeader, variableHeader, payload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MqttPublishVariableHeader variableHeader() {
|
||||
return (MqttPublishVariableHeader) super.variableHeader();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf payload() {
|
||||
return content();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf content() {
|
||||
final ByteBuf data = (ByteBuf) super.payload();
|
||||
if (data.refCnt() <= 0) {
|
||||
throw new IllegalReferenceCountException(data.refCnt());
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MqttPublishMessage copy() {
|
||||
return replace(content().copy());
|
||||
}
|
||||
|
||||
@Override
|
||||
public MqttPublishMessage duplicate() {
|
||||
return replace(content().duplicate());
|
||||
}
|
||||
|
||||
@Override
|
||||
public MqttPublishMessage retainedDuplicate() {
|
||||
return replace(content().retainedDuplicate());
|
||||
}
|
||||
|
||||
@Override
|
||||
public MqttPublishMessage replace(ByteBuf content) {
|
||||
return new MqttPublishMessage(fixedHeader(), variableHeader(), content);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int refCnt() {
|
||||
return content().refCnt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MqttPublishMessage retain() {
|
||||
content().retain();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MqttPublishMessage retain(int increment) {
|
||||
content().retain(increment);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MqttPublishMessage touch() {
|
||||
content().touch();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MqttPublishMessage touch(Object hint) {
|
||||
content().touch(hint);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean release() {
|
||||
return content().release();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean release(int decrement) {
|
||||
return content().release(decrement);
|
||||
}
|
||||
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2014 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you 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 io.netty.handler.codec.mqtt;
|
||||
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
/**
|
||||
* Variable Header of the {@link MqttPublishMessage}
|
||||
*/
|
||||
public final class MqttPublishVariableHeader {
|
||||
|
||||
private final String topicName;
|
||||
private final int packetId;
|
||||
|
||||
public MqttPublishVariableHeader(String topicName, int packetId) {
|
||||
this.topicName = topicName;
|
||||
this.packetId = packetId;
|
||||
}
|
||||
|
||||
public String topicName() {
|
||||
return topicName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #packetId()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public int messageId() {
|
||||
return packetId;
|
||||
}
|
||||
|
||||
public int packetId() {
|
||||
return packetId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder(StringUtil.simpleClassName(this))
|
||||
.append('[')
|
||||
.append("topicName=").append(topicName)
|
||||
.append(", packetId=").append(packetId)
|
||||
.append(']')
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2014 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you 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 io.netty.handler.codec.mqtt;
|
||||
|
||||
public enum MqttQoS {
|
||||
AT_MOST_ONCE(0),
|
||||
AT_LEAST_ONCE(1),
|
||||
EXACTLY_ONCE(2),
|
||||
FAILURE(0x80);
|
||||
|
||||
private final int value;
|
||||
|
||||
MqttQoS(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int value() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static MqttQoS valueOf(int value) {
|
||||
for (MqttQoS q: values()) {
|
||||
if (q.value == value) {
|
||||
return q;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("invalid QoS: " + value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2014 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you 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 io.netty.handler.codec.mqtt;
|
||||
|
||||
/**
|
||||
* See <a href="http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#suback">MQTTV3.1/suback</a>
|
||||
*/
|
||||
public final class MqttSubAckMessage extends MqttMessage {
|
||||
|
||||
public MqttSubAckMessage(
|
||||
MqttFixedHeader mqttFixedHeader,
|
||||
MqttMessageIdVariableHeader variableHeader,
|
||||
MqttSubAckPayload payload) {
|
||||
super(mqttFixedHeader, variableHeader, payload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MqttMessageIdVariableHeader variableHeader() {
|
||||
return (MqttMessageIdVariableHeader) super.variableHeader();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MqttSubAckPayload payload() {
|
||||
return (MqttSubAckPayload) super.payload();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2014 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you 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 io.netty.handler.codec.mqtt;
|
||||
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Payload of the {@link MqttSubAckMessage}
|
||||
*/
|
||||
public class MqttSubAckPayload {
|
||||
|
||||
private final List<Integer> grantedQoSLevels;
|
||||
|
||||
public MqttSubAckPayload(int... grantedQoSLevels) {
|
||||
if (grantedQoSLevels == null) {
|
||||
throw new NullPointerException("grantedQoSLevels");
|
||||
}
|
||||
|
||||
List<Integer> list = new ArrayList<Integer>(grantedQoSLevels.length);
|
||||
for (int v: grantedQoSLevels) {
|
||||
list.add(v);
|
||||
}
|
||||
this.grantedQoSLevels = Collections.unmodifiableList(list);
|
||||
}
|
||||
|
||||
public MqttSubAckPayload(Iterable<Integer> grantedQoSLevels) {
|
||||
if (grantedQoSLevels == null) {
|
||||
throw new NullPointerException("grantedQoSLevels");
|
||||
}
|
||||
List<Integer> list = new ArrayList<Integer>();
|
||||
for (Integer v: grantedQoSLevels) {
|
||||
if (v == null) {
|
||||
break;
|
||||
}
|
||||
list.add(v);
|
||||
}
|
||||
this.grantedQoSLevels = Collections.unmodifiableList(list);
|
||||
}
|
||||
|
||||
public List<Integer> grantedQoSLevels() {
|
||||
return grantedQoSLevels;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder(StringUtil.simpleClassName(this))
|
||||
.append('[')
|
||||
.append("grantedQoSLevels=").append(grantedQoSLevels)
|
||||
.append(']')
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2014 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you 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 io.netty.handler.codec.mqtt;
|
||||
|
||||
/**
|
||||
* See <a href="http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#subscribe">
|
||||
* MQTTV3.1/subscribe</a>
|
||||
*/
|
||||
public final class MqttSubscribeMessage extends MqttMessage {
|
||||
|
||||
public MqttSubscribeMessage(
|
||||
MqttFixedHeader mqttFixedHeader,
|
||||
MqttMessageIdVariableHeader variableHeader,
|
||||
MqttSubscribePayload payload) {
|
||||
super(mqttFixedHeader, variableHeader, payload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MqttMessageIdVariableHeader variableHeader() {
|
||||
return (MqttMessageIdVariableHeader) super.variableHeader();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MqttSubscribePayload payload() {
|
||||
return (MqttSubscribePayload) super.payload();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2014 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you 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 io.netty.handler.codec.mqtt;
|
||||
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Payload of the {@link MqttSubscribeMessage}
|
||||
*/
|
||||
public final class MqttSubscribePayload {
|
||||
|
||||
private final List<MqttTopicSubscription> topicSubscriptions;
|
||||
|
||||
public MqttSubscribePayload(List<MqttTopicSubscription> topicSubscriptions) {
|
||||
this.topicSubscriptions = Collections.unmodifiableList(topicSubscriptions);
|
||||
}
|
||||
|
||||
public List<MqttTopicSubscription> topicSubscriptions() {
|
||||
return topicSubscriptions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder(StringUtil.simpleClassName(this)).append('[');
|
||||
for (int i = 0; i < topicSubscriptions.size() - 1; i++) {
|
||||
builder.append(topicSubscriptions.get(i)).append(", ");
|
||||
}
|
||||
builder.append(topicSubscriptions.get(topicSubscriptions.size() - 1));
|
||||
builder.append(']');
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2014 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you 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 io.netty.handler.codec.mqtt;
|
||||
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
/**
|
||||
* Contains a topic name and Qos Level.
|
||||
* This is part of the {@link MqttSubscribePayload}
|
||||
*/
|
||||
public final class MqttTopicSubscription {
|
||||
|
||||
private final String topicFilter;
|
||||
private final MqttQoS qualityOfService;
|
||||
|
||||
public MqttTopicSubscription(String topicFilter, MqttQoS qualityOfService) {
|
||||
this.topicFilter = topicFilter;
|
||||
this.qualityOfService = qualityOfService;
|
||||
}
|
||||
|
||||
public String topicName() {
|
||||
return topicFilter;
|
||||
}
|
||||
|
||||
public MqttQoS qualityOfService() {
|
||||
return qualityOfService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder(StringUtil.simpleClassName(this))
|
||||
.append('[')
|
||||
.append("topicFilter=").append(topicFilter)
|
||||
.append(", qualityOfService=").append(qualityOfService)
|
||||
.append(']')
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
Executable
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2014 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you 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 io.netty.handler.codec.mqtt;
|
||||
|
||||
import io.netty.handler.codec.DecoderException;
|
||||
|
||||
/**
|
||||
* A {@link MqttUnacceptableProtocolVersionException} which is thrown when
|
||||
* a CONNECT request contains unacceptable protocol version.
|
||||
*/
|
||||
public final class MqttUnacceptableProtocolVersionException extends DecoderException {
|
||||
|
||||
private static final long serialVersionUID = 4914652213232455749L;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*/
|
||||
public MqttUnacceptableProtocolVersionException() { }
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*/
|
||||
public MqttUnacceptableProtocolVersionException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*/
|
||||
public MqttUnacceptableProtocolVersionException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*/
|
||||
public MqttUnacceptableProtocolVersionException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2014 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you 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 io.netty.handler.codec.mqtt;
|
||||
|
||||
/**
|
||||
* See <a href="http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#unsuback">MQTTV3.1/unsuback</a>
|
||||
*/
|
||||
public final class MqttUnsubAckMessage extends MqttMessage {
|
||||
|
||||
public MqttUnsubAckMessage(MqttFixedHeader mqttFixedHeader, MqttMessageIdVariableHeader variableHeader) {
|
||||
super(mqttFixedHeader, variableHeader, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MqttMessageIdVariableHeader variableHeader() {
|
||||
return (MqttMessageIdVariableHeader) super.variableHeader();
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2014 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you 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 io.netty.handler.codec.mqtt;
|
||||
|
||||
/**
|
||||
* See <a href="http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#unsubscribe">
|
||||
* MQTTV3.1/unsubscribe</a>
|
||||
*/
|
||||
public final class MqttUnsubscribeMessage extends MqttMessage {
|
||||
|
||||
public MqttUnsubscribeMessage(
|
||||
MqttFixedHeader mqttFixedHeader,
|
||||
MqttMessageIdVariableHeader variableHeader,
|
||||
MqttUnsubscribePayload payload) {
|
||||
super(mqttFixedHeader, variableHeader, payload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MqttMessageIdVariableHeader variableHeader() {
|
||||
return (MqttMessageIdVariableHeader) super.variableHeader();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MqttUnsubscribePayload payload() {
|
||||
return (MqttUnsubscribePayload) super.payload();
|
||||
}
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2014 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you 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 io.netty.handler.codec.mqtt;
|
||||
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Payload of the {@link MqttUnsubscribeMessage}
|
||||
*/
|
||||
public final class MqttUnsubscribePayload {
|
||||
|
||||
private final List<String> topics;
|
||||
|
||||
public MqttUnsubscribePayload(List<String> topics) {
|
||||
this.topics = Collections.unmodifiableList(topics);
|
||||
}
|
||||
|
||||
public List<String> topics() {
|
||||
return topics;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder(StringUtil.simpleClassName(this)).append('[');
|
||||
for (int i = 0; i < topics.size() - 1; i++) {
|
||||
builder.append("topicName = ").append(topics.get(i)).append(", ");
|
||||
}
|
||||
builder.append("topicName = ").append(topics.get(topics.size() - 1))
|
||||
.append(']');
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2014 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you 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 io.netty.handler.codec.mqtt;
|
||||
|
||||
import io.netty.util.CharsetUtil;
|
||||
import io.netty.util.internal.ObjectUtil;
|
||||
|
||||
/**
|
||||
* Mqtt version specific constant values used by multiple classes in mqtt-codec.
|
||||
*/
|
||||
public enum MqttVersion {
|
||||
MQTT_3_1("MQIsdp", (byte) 3),
|
||||
MQTT_3_1_1("MQTT", (byte) 4);
|
||||
|
||||
private final String name;
|
||||
private final byte level;
|
||||
|
||||
MqttVersion(String protocolName, byte protocolLevel) {
|
||||
name = ObjectUtil.checkNotNull(protocolName, "protocolName");
|
||||
level = protocolLevel;
|
||||
}
|
||||
|
||||
public String protocolName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public byte[] protocolNameBytes() {
|
||||
return name.getBytes(CharsetUtil.UTF_8);
|
||||
}
|
||||
|
||||
public byte protocolLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public static MqttVersion fromProtocolNameAndLevel(String protocolName, byte protocolLevel) {
|
||||
for (MqttVersion mv : values()) {
|
||||
if (mv.name.equals(protocolName)) {
|
||||
if (mv.level == protocolLevel) {
|
||||
return mv;
|
||||
} else {
|
||||
throw new MqttUnacceptableProtocolVersionException(protocolName + " and " +
|
||||
protocolLevel + " are not match");
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new MqttUnacceptableProtocolVersionException(protocolName + "is unknown protocol name");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2014 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Encoder, decoder and different Message Types for MQTT.
|
||||
*/
|
||||
package io.netty.handler.codec.mqtt;
|
||||
Reference in New Issue
Block a user