MqttMsgBase.cs 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. /*
  2. Copyright (c) 2013, 2014 Paolo Patierno
  3. All rights reserved. This program and the accompanying materials
  4. are made available under the terms of the Eclipse Public License v1.0
  5. and Eclipse Distribution License v1.0 which accompany this distribution.
  6. The Eclipse Public License is available at
  7. http://www.eclipse.org/legal/epl-v10.html
  8. and the Eclipse Distribution License is available at
  9. http://www.eclipse.org/org/documents/edl-v10.php.
  10. Contributors:
  11. Paolo Patierno - initial API and implementation and/or initial documentation
  12. */
  13. using System;
  14. using System.Text;
  15. namespace uPLibrary.Networking.M2Mqtt.Messages
  16. {
  17. /// <summary>
  18. /// Base class for all MQTT messages
  19. /// </summary>
  20. public abstract class MqttMsgBase
  21. {
  22. #region Constants...
  23. // mask, offset and size for fixed header fields
  24. internal const byte MSG_TYPE_MASK = 0xF0;
  25. internal const byte MSG_TYPE_OFFSET = 0x04;
  26. internal const byte MSG_TYPE_SIZE = 0x04;
  27. internal const byte MSG_FLAG_BITS_MASK = 0x0F; // [v3.1.1]
  28. internal const byte MSG_FLAG_BITS_OFFSET = 0x00; // [v3.1.1]
  29. internal const byte MSG_FLAG_BITS_SIZE = 0x04; // [v3.1.1]
  30. internal const byte DUP_FLAG_MASK = 0x08;
  31. internal const byte DUP_FLAG_OFFSET = 0x03;
  32. internal const byte DUP_FLAG_SIZE = 0x01;
  33. internal const byte QOS_LEVEL_MASK = 0x06;
  34. internal const byte QOS_LEVEL_OFFSET = 0x01;
  35. internal const byte QOS_LEVEL_SIZE = 0x02;
  36. internal const byte RETAIN_FLAG_MASK = 0x01;
  37. internal const byte RETAIN_FLAG_OFFSET = 0x00;
  38. internal const byte RETAIN_FLAG_SIZE = 0x01;
  39. // MQTT message types
  40. internal const byte MQTT_MSG_CONNECT_TYPE = 0x01;
  41. internal const byte MQTT_MSG_CONNACK_TYPE = 0x02;
  42. internal const byte MQTT_MSG_PUBLISH_TYPE = 0x03;
  43. internal const byte MQTT_MSG_PUBACK_TYPE = 0x04;
  44. internal const byte MQTT_MSG_PUBREC_TYPE = 0x05;
  45. internal const byte MQTT_MSG_PUBREL_TYPE = 0x06;
  46. internal const byte MQTT_MSG_PUBCOMP_TYPE = 0x07;
  47. internal const byte MQTT_MSG_SUBSCRIBE_TYPE = 0x08;
  48. internal const byte MQTT_MSG_SUBACK_TYPE = 0x09;
  49. internal const byte MQTT_MSG_UNSUBSCRIBE_TYPE = 0x0A;
  50. internal const byte MQTT_MSG_UNSUBACK_TYPE = 0x0B;
  51. internal const byte MQTT_MSG_PINGREQ_TYPE = 0x0C;
  52. internal const byte MQTT_MSG_PINGRESP_TYPE = 0x0D;
  53. internal const byte MQTT_MSG_DISCONNECT_TYPE = 0x0E;
  54. // [v3.1.1] MQTT flag bits
  55. internal const byte MQTT_MSG_CONNECT_FLAG_BITS = 0x00;
  56. internal const byte MQTT_MSG_CONNACK_FLAG_BITS = 0x00;
  57. internal const byte MQTT_MSG_PUBLISH_FLAG_BITS = 0x00; // just defined as 0x00 but depends on publish props (dup, qos, retain)
  58. internal const byte MQTT_MSG_PUBACK_FLAG_BITS = 0x00;
  59. internal const byte MQTT_MSG_PUBREC_FLAG_BITS = 0x00;
  60. internal const byte MQTT_MSG_PUBREL_FLAG_BITS = 0x02;
  61. internal const byte MQTT_MSG_PUBCOMP_FLAG_BITS = 0x00;
  62. internal const byte MQTT_MSG_SUBSCRIBE_FLAG_BITS = 0x02;
  63. internal const byte MQTT_MSG_SUBACK_FLAG_BITS = 0x00;
  64. internal const byte MQTT_MSG_UNSUBSCRIBE_FLAG_BITS = 0x02;
  65. internal const byte MQTT_MSG_UNSUBACK_FLAG_BITS = 0x00;
  66. internal const byte MQTT_MSG_PINGREQ_FLAG_BITS = 0x00;
  67. internal const byte MQTT_MSG_PINGRESP_FLAG_BITS = 0x00;
  68. internal const byte MQTT_MSG_DISCONNECT_FLAG_BITS = 0x00;
  69. // QOS levels
  70. public const byte QOS_LEVEL_AT_MOST_ONCE = 0x00;
  71. public const byte QOS_LEVEL_AT_LEAST_ONCE = 0x01;
  72. public const byte QOS_LEVEL_EXACTLY_ONCE = 0x02;
  73. // SUBSCRIBE QoS level granted failure [v3.1.1]
  74. public const byte QOS_LEVEL_GRANTED_FAILURE = 0x80;
  75. internal const ushort MAX_TOPIC_LENGTH = 65535;
  76. internal const ushort MIN_TOPIC_LENGTH = 1;
  77. internal const byte MESSAGE_ID_SIZE = 2;
  78. #endregion
  79. #region Properties...
  80. /// <summary>
  81. /// Message type
  82. /// </summary>
  83. public byte Type
  84. {
  85. get { return this.type; }
  86. set { this.type = value; }
  87. }
  88. /// <summary>
  89. /// Duplicate message flag
  90. /// </summary>
  91. public bool DupFlag
  92. {
  93. get { return this.dupFlag; }
  94. set { this.dupFlag = value; }
  95. }
  96. /// <summary>
  97. /// Quality of Service level
  98. /// </summary>
  99. public byte QosLevel
  100. {
  101. get { return this.qosLevel; }
  102. set { this.qosLevel = value; }
  103. }
  104. /// <summary>
  105. /// Retain message flag
  106. /// </summary>
  107. public bool Retain
  108. {
  109. get { return this.retain; }
  110. set { this.retain = value; }
  111. }
  112. /// <summary>
  113. /// Message identifier for the message
  114. /// </summary>
  115. public ushort MessageId
  116. {
  117. get { return this.messageId; }
  118. set { this.messageId = value; }
  119. }
  120. #endregion
  121. // message type
  122. protected byte type;
  123. // duplicate delivery
  124. protected bool dupFlag;
  125. // quality of service level
  126. protected byte qosLevel;
  127. // retain flag
  128. protected bool retain;
  129. // message identifier
  130. protected ushort messageId;
  131. /// <summary>
  132. /// Returns message bytes rapresentation
  133. /// </summary>
  134. /// <param name="protocolVersion">Protocol version</param>
  135. /// <returns>Bytes rapresentation</returns>
  136. public abstract byte[] GetBytes(byte protocolVersion);
  137. /// <summary>
  138. /// Encode remaining length and insert it into message buffer
  139. /// </summary>
  140. /// <param name="remainingLength">Remaining length value to encode</param>
  141. /// <param name="buffer">Message buffer for inserting encoded value</param>
  142. /// <param name="index">Index from which insert encoded value into buffer</param>
  143. /// <returns>Index updated</returns>
  144. protected int encodeRemainingLength(int remainingLength, byte[] buffer, int index)
  145. {
  146. int digit = 0;
  147. do
  148. {
  149. digit = remainingLength % 128;
  150. remainingLength /= 128;
  151. if (remainingLength > 0)
  152. digit = digit | 0x80;
  153. buffer[index++] = (byte)digit;
  154. } while (remainingLength > 0);
  155. return index;
  156. }
  157. /// <summary>
  158. /// Decode remaining length reading bytes from socket
  159. /// </summary>
  160. /// <param name="channel">Channel from reading bytes</param>
  161. /// <returns>Decoded remaining length</returns>
  162. protected static int decodeRemainingLength(IMqttNetworkChannel channel)
  163. {
  164. int multiplier = 1;
  165. int value = 0;
  166. int digit = 0;
  167. byte[] nextByte = new byte[1];
  168. do
  169. {
  170. // next digit from stream
  171. channel.Receive(nextByte);
  172. digit = nextByte[0];
  173. value += ((digit & 127) * multiplier);
  174. multiplier *= 128;
  175. } while ((digit & 128) != 0);
  176. return value;
  177. }
  178. #if TRACE
  179. /// <summary>
  180. /// Returns a string representation of the message for tracing
  181. /// </summary>
  182. /// <param name="name">Message name</param>
  183. /// <param name="fieldNames">Message fields name</param>
  184. /// <param name="fieldValues">Message fields value</param>
  185. /// <returns>String representation of the message</returns>
  186. protected string GetTraceString(string name, object[] fieldNames, object[] fieldValues)
  187. {
  188. StringBuilder sb = new StringBuilder();
  189. sb.Append(name);
  190. if ((fieldNames != null) && (fieldValues != null))
  191. {
  192. sb.Append("(");
  193. bool addComma = false;
  194. for (int i = 0; i < fieldValues.Length; i++)
  195. {
  196. if (fieldValues[i] != null)
  197. {
  198. if (addComma)
  199. {
  200. sb.Append(",");
  201. }
  202. sb.Append(fieldNames[i]);
  203. sb.Append(":");
  204. sb.Append(GetStringObject(fieldValues[i]));
  205. addComma = true;
  206. }
  207. }
  208. sb.Append(")");
  209. }
  210. return sb.ToString();
  211. }
  212. object GetStringObject(object value)
  213. {
  214. byte[] binary = value as byte[];
  215. if (binary != null)
  216. {
  217. string hexChars = "0123456789ABCDEF";
  218. StringBuilder sb = new StringBuilder(binary.Length * 2);
  219. for (int i = 0; i < binary.Length; ++i)
  220. {
  221. sb.Append(hexChars[binary[i] >> 4]);
  222. sb.Append(hexChars[binary[i] & 0x0F]);
  223. }
  224. return sb.ToString();
  225. }
  226. object[] list = value as object[];
  227. if (list != null)
  228. {
  229. StringBuilder sb = new StringBuilder();
  230. sb.Append('[');
  231. for (int i = 0; i < list.Length; ++i)
  232. {
  233. if (i > 0) sb.Append(',');
  234. sb.Append(list[i]);
  235. }
  236. sb.Append(']');
  237. return sb.ToString();
  238. }
  239. return value;
  240. }
  241. #endif
  242. }
  243. }