1 /* 2 * Collie - An asynchronous event-driven network framework using Dlang development 3 * 4 * Copyright (C) 2015-2017 Shanghai Putao Technology Co., Ltd 5 * 6 * Developer: putao's Dlang team 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 module collie.codec.mqtt.mqttcodecutil; 12 13 import kiss.log; 14 import std.conv; 15 import std.stdio; 16 import std..string; 17 import std.array; 18 import collie.codec.mqtt.mqttversion; 19 import collie.codec.mqtt.mqttfixedheader; 20 import collie.codec.mqtt.mqttmsgtype; 21 import collie.codec.mqtt.mqttqos; 22 23 class MqttCodecUtil 24 { 25 static bool isValidPublishTopicName(string topicName) { 26 // publish topic name must not contain any wildcard 27 foreach (char c ; TOPIC_WILDCARDS) { 28 if (indexOf(topicName,c) >= 0) { 29 return false; 30 } 31 } 32 return true; 33 } 34 35 static bool isValidMessageId(int messageId) { 36 return messageId != 0; 37 } 38 39 static bool isValidClientId(MqttVersion mqttVersion, string clientId) { 40 if (mqttVersion.protocolName() == "MQIsdp") { 41 return clientId != null && clientId.length >= MIN_CLIENT_ID_LENGTH && 42 clientId.length <= MAX_CLIENT_ID_LENGTH; 43 } 44 if (mqttVersion.protocolName() == "MQTT") { 45 // In 3.1.3.1 Client Identifier of MQTT 3.1.1 specification, The Server MAY allow ClientId’s 46 // that contain more than 23 encoded bytes. And, The Server MAY allow zero-length ClientId. 47 return clientId != null; 48 } 49 50 logDebug(to!string(mqttVersion) ~ " is unknown mqtt version"); 51 return false; 52 } 53 54 static MqttFixedHeader validateFixedHeader(MqttFixedHeader mqttFixedHeader) { 55 switch (mqttFixedHeader.messageType()) { 56 case MqttMsgType.PUBREL: 57 case MqttMsgType.SUBSCRIBE: 58 case MqttMsgType.UNSUBSCRIBE: 59 if (mqttFixedHeader.qosLevel() != MqttQoS.AT_LEAST_ONCE) { 60 61 throw new Exception(to!string(mqttFixedHeader.messageType()) ~ " message must have QoS 1"); 62 } 63 return mqttFixedHeader; 64 default: 65 return mqttFixedHeader; 66 } 67 } 68 69 static MqttFixedHeader resetUnusedFields(MqttFixedHeader mqttFixedHeader) { 70 switch (mqttFixedHeader.messageType()) { 71 case MqttMsgType.CONNECT: 72 case MqttMsgType.CONNACK: 73 case MqttMsgType.PUBACK: 74 case MqttMsgType.PUBREC: 75 case MqttMsgType.PUBCOMP: 76 case MqttMsgType.SUBACK: 77 case MqttMsgType.UNSUBACK: 78 case MqttMsgType.PINGREQ: 79 case MqttMsgType.PINGRESP: 80 case MqttMsgType.DISCONNECT: 81 if (mqttFixedHeader.isDup() || 82 mqttFixedHeader.qosLevel() != MqttQoS.AT_MOST_ONCE || 83 mqttFixedHeader.isRetain()) { 84 return new MqttFixedHeader( 85 mqttFixedHeader.messageType(), 86 false, 87 MqttQoS.AT_MOST_ONCE, 88 false, 89 mqttFixedHeader.remainingLength()); 90 } 91 return mqttFixedHeader; 92 case MqttMsgType.PUBREL: 93 case MqttMsgType.SUBSCRIBE: 94 case MqttMsgType.UNSUBSCRIBE: 95 if (mqttFixedHeader.isRetain()) { 96 return new MqttFixedHeader( 97 mqttFixedHeader.messageType(), 98 mqttFixedHeader.isDup(), 99 mqttFixedHeader.qosLevel(), 100 false, 101 mqttFixedHeader.remainingLength()); 102 } 103 return mqttFixedHeader; 104 default: 105 return mqttFixedHeader; 106 } 107 } 108 109 private: 110 this() { } 111 private: 112 static char[] TOPIC_WILDCARDS = array(['#', '+'][]); 113 static int MIN_CLIENT_ID_LENGTH = 1; 114 static int MAX_CLIENT_ID_LENGTH = 23; 115 } 116