/* * 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() { } }