MqttMsgBase.cs 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  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 DUP_FLAG_MASK = 0x08;
  28. internal const byte DUP_FLAG_OFFSET = 0x03;
  29. internal const byte DUP_FLAG_SIZE = 0x01;
  30. internal const byte QOS_LEVEL_MASK = 0x06;
  31. internal const byte QOS_LEVEL_OFFSET = 0x01;
  32. internal const byte QOS_LEVEL_SIZE = 0x02;
  33. internal const byte RETAIN_FLAG_MASK = 0x01;
  34. internal const byte RETAIN_FLAG_OFFSET = 0x00;
  35. internal const byte RETAIN_FLAG_SIZE = 0x01;
  36. // MQTT message types
  37. internal const byte MQTT_MSG_CONNECT_TYPE = 0x01;
  38. internal const byte MQTT_MSG_CONNACK_TYPE = 0x02;
  39. internal const byte MQTT_MSG_PUBLISH_TYPE = 0x03;
  40. internal const byte MQTT_MSG_PUBACK_TYPE = 0x04;
  41. internal const byte MQTT_MSG_PUBREC_TYPE = 0x05;
  42. internal const byte MQTT_MSG_PUBREL_TYPE = 0x06;
  43. internal const byte MQTT_MSG_PUBCOMP_TYPE = 0x07;
  44. internal const byte MQTT_MSG_SUBSCRIBE_TYPE = 0x08;
  45. internal const byte MQTT_MSG_SUBACK_TYPE = 0x09;
  46. internal const byte MQTT_MSG_UNSUBSCRIBE_TYPE = 0x0A;
  47. internal const byte MQTT_MSG_UNSUBACK_TYPE = 0x0B;
  48. internal const byte MQTT_MSG_PINGREQ_TYPE = 0x0C;
  49. internal const byte MQTT_MSG_PINGRESP_TYPE = 0x0D;
  50. internal const byte MQTT_MSG_DISCONNECT_TYPE = 0x0E;
  51. // QOS levels
  52. public const byte QOS_LEVEL_AT_MOST_ONCE = 0x00;
  53. public const byte QOS_LEVEL_AT_LEAST_ONCE = 0x01;
  54. public const byte QOS_LEVEL_EXACTLY_ONCE = 0x02;
  55. internal const ushort MAX_TOPIC_LENGTH = 65535;
  56. internal const ushort MIN_TOPIC_LENGTH = 1;
  57. internal const byte MESSAGE_ID_SIZE = 2;
  58. #endregion
  59. #region Properties...
  60. /// <summary>
  61. /// Message type
  62. /// </summary>
  63. public byte Type
  64. {
  65. get { return this.type; }
  66. set { this.type = value; }
  67. }
  68. /// <summary>
  69. /// Duplicate message flag
  70. /// </summary>
  71. public bool DupFlag
  72. {
  73. get { return this.dupFlag; }
  74. set { this.dupFlag = value; }
  75. }
  76. /// <summary>
  77. /// Quality of Service level
  78. /// </summary>
  79. public byte QosLevel
  80. {
  81. get { return this.qosLevel; }
  82. set { this.qosLevel = value; }
  83. }
  84. /// <summary>
  85. /// Retain message flag
  86. /// </summary>
  87. public bool Retain
  88. {
  89. get { return this.retain; }
  90. set { this.retain = value; }
  91. }
  92. #endregion
  93. // message type
  94. protected byte type;
  95. // duplicate delivery
  96. protected bool dupFlag;
  97. // quality of service level
  98. protected byte qosLevel;
  99. // retain flag
  100. protected bool retain;
  101. /// <summary>
  102. /// Returns message bytes rapresentation
  103. /// </summary>
  104. /// <returns>Bytes rapresentation</returns>
  105. public abstract byte[] GetBytes();
  106. /// <summary>
  107. /// Encode remaining length and insert it into message buffer
  108. /// </summary>
  109. /// <param name="remainingLength">Remaining length value to encode</param>
  110. /// <param name="buffer">Message buffer for inserting encoded value</param>
  111. /// <param name="index">Index from which insert encoded value into buffer</param>
  112. /// <returns>Index updated</returns>
  113. protected int encodeRemainingLength(int remainingLength, byte[] buffer, int index)
  114. {
  115. int digit = 0;
  116. do
  117. {
  118. digit = remainingLength % 128;
  119. remainingLength /= 128;
  120. if (remainingLength > 0)
  121. digit = digit | 0x80;
  122. buffer[index++] = (byte)digit;
  123. } while (remainingLength > 0);
  124. return index;
  125. }
  126. /// <summary>
  127. /// Decode remaining length reading bytes from socket
  128. /// </summary>
  129. /// <param name="channel">Channel from reading bytes</param>
  130. /// <returns>Decoded remaining length</returns>
  131. protected static int decodeRemainingLength(IMqttNetworkChannel channel)
  132. {
  133. int multiplier = 1;
  134. int value = 0;
  135. int digit = 0;
  136. byte[] nextByte = new byte[1];
  137. do
  138. {
  139. // next digit from stream
  140. channel.Receive(nextByte);
  141. digit = nextByte[0];
  142. value += ((digit & 127) * multiplier);
  143. multiplier *= 128;
  144. } while ((digit & 128) != 0);
  145. return value;
  146. }
  147. #if TRACE
  148. /// <summary>
  149. /// Returns a string representation of the message for tracing
  150. /// </summary>
  151. /// <param name="name">Message name</param>
  152. /// <param name="fieldNames">Message fields name</param>
  153. /// <param name="fieldValues">Message fields value</param>
  154. /// <returns>String representation of the message</returns>
  155. protected string GetTraceString(string name, object[] fieldNames, object[] fieldValues)
  156. {
  157. StringBuilder sb = new StringBuilder();
  158. sb.Append(name);
  159. if ((fieldNames != null) && (fieldValues != null))
  160. {
  161. sb.Append("(");
  162. bool addComma = false;
  163. for (int i = 0; i < fieldValues.Length; i++)
  164. {
  165. if (fieldValues[i] != null)
  166. {
  167. if (addComma)
  168. {
  169. sb.Append(",");
  170. }
  171. sb.Append(fieldNames[i]);
  172. sb.Append(":");
  173. sb.Append(GetStringObject(fieldValues[i]));
  174. addComma = true;
  175. }
  176. }
  177. sb.Append(")");
  178. }
  179. return sb.ToString();
  180. }
  181. object GetStringObject(object value)
  182. {
  183. byte[] binary = value as byte[];
  184. if (binary != null)
  185. {
  186. string hexChars = "0123456789ABCDEF";
  187. StringBuilder sb = new StringBuilder(binary.Length * 2);
  188. for (int i = 0; i < binary.Length; ++i)
  189. {
  190. sb.Append(hexChars[binary[i] >> 4]);
  191. sb.Append(hexChars[binary[i] & 0x0F]);
  192. }
  193. return sb.ToString();
  194. }
  195. object[] list = value as object[];
  196. if (list != null)
  197. {
  198. StringBuilder sb = new StringBuilder();
  199. sb.Append('[');
  200. for (int i = 0; i < list.Length; ++i)
  201. {
  202. if (i > 0) sb.Append(',');
  203. sb.Append(list[i]);
  204. }
  205. sb.Append(']');
  206. return sb.ToString();
  207. }
  208. return value;
  209. }
  210. #endif
  211. }
  212. }