Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 
 
 
 

510 wiersze
19 KiB

  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Text;
  6. using MQTTnet.Core.Adapter;
  7. using MQTTnet.Core.Exceptions;
  8. using MQTTnet.Core.Packets;
  9. using MQTTnet.Core.Protocol;
  10. namespace MQTTnet.Core.Serializer
  11. {
  12. public sealed class MqttPacketSerializer : IMqttPacketSerializer
  13. {
  14. private static byte[] ProtocolVersionV311Name { get; } = Encoding.UTF8.GetBytes("MQTT");
  15. private static byte[] ProtocolVersionV310Name { get; } = Encoding.UTF8.GetBytes("MQIs");
  16. public MqttProtocolVersion ProtocolVersion { get; set; } = MqttProtocolVersion.V311;
  17. public byte[] Serialize(MqttBasePacket packet)
  18. {
  19. if (packet == null) throw new ArgumentNullException(nameof(packet));
  20. using (var stream = new MemoryStream())
  21. using (var writer = new MqttPacketWriter(stream))
  22. {
  23. var header = new List<byte> { SerializePacket(packet, writer) };
  24. var body = stream.ToArray();
  25. MqttPacketWriter.BuildLengthHeader(body.Length, header);
  26. var headerArray = header.ToArray();
  27. var writeBuffer = new byte[header.Count + body.Length];
  28. Buffer.BlockCopy(headerArray, 0, writeBuffer, 0, headerArray.Length);
  29. Buffer.BlockCopy(body, 0, writeBuffer, headerArray.Length, body.Length);
  30. return writeBuffer;
  31. }
  32. }
  33. public MqttBasePacket Deserialize(ReceivedMqttPacket receivedMqttPacket)
  34. {
  35. if (receivedMqttPacket == null) throw new ArgumentNullException(nameof(receivedMqttPacket));
  36. using (var reader = new MqttPacketReader(receivedMqttPacket))
  37. {
  38. return Deserialize(receivedMqttPacket.Header, reader);
  39. }
  40. }
  41. private byte SerializePacket(MqttBasePacket packet, MqttPacketWriter writer)
  42. {
  43. switch (packet)
  44. {
  45. case MqttConnectPacket connectPacket: return Serialize(connectPacket, writer);
  46. case MqttConnAckPacket connAckPacket: return Serialize(connAckPacket, writer);
  47. case MqttDisconnectPacket _: return SerializeEmptyPacket(MqttControlPacketType.Disconnect);
  48. case MqttPingReqPacket _: return SerializeEmptyPacket(MqttControlPacketType.PingReq);
  49. case MqttPingRespPacket _: return SerializeEmptyPacket(MqttControlPacketType.PingResp);
  50. case MqttPublishPacket publishPacket: return Serialize(publishPacket, writer);
  51. case MqttPubAckPacket pubAckPacket: return Serialize(pubAckPacket, writer);
  52. case MqttPubRecPacket pubRecPacket: return Serialize(pubRecPacket, writer);
  53. case MqttPubRelPacket pubRelPacket: return Serialize(pubRelPacket, writer);
  54. case MqttPubCompPacket pubCompPacket: return Serialize(pubCompPacket, writer);
  55. case MqttSubscribePacket subscribePacket: return Serialize(subscribePacket, writer);
  56. case MqttSubAckPacket subAckPacket: return Serialize(subAckPacket, writer);
  57. case MqttUnsubscribePacket unsubscribePacket: return Serialize(unsubscribePacket, writer);
  58. case MqttUnsubAckPacket unsubAckPacket: return Serialize(unsubAckPacket, writer);
  59. default: throw new MqttProtocolViolationException("Packet type invalid.");
  60. }
  61. }
  62. private static MqttBasePacket Deserialize(MqttPacketHeader header, MqttPacketReader reader)
  63. {
  64. switch (header.ControlPacketType)
  65. {
  66. case MqttControlPacketType.Connect: return DeserializeConnect(reader);
  67. case MqttControlPacketType.ConnAck: return DeserializeConnAck(reader);
  68. case MqttControlPacketType.Disconnect: return new MqttDisconnectPacket();
  69. case MqttControlPacketType.Publish: return DeserializePublish(reader, header);
  70. case MqttControlPacketType.PubAck: return DeserializePubAck(reader);
  71. case MqttControlPacketType.PubRec: return DeserializePubRec(reader);
  72. case MqttControlPacketType.PubRel: return DeserializePubRel(reader);
  73. case MqttControlPacketType.PubComp: return DeserializePubComp(reader);
  74. case MqttControlPacketType.PingReq: return new MqttPingReqPacket();
  75. case MqttControlPacketType.PingResp: return new MqttPingRespPacket();
  76. case MqttControlPacketType.Subscribe: return DeserializeSubscribe(reader);
  77. case MqttControlPacketType.SubAck: return DeserializeSubAck(reader);
  78. case MqttControlPacketType.Unsubscibe: return DeserializeUnsubscribe(reader);
  79. case MqttControlPacketType.UnsubAck: return DeserializeUnsubAck(reader);
  80. default: throw new MqttProtocolViolationException($"Packet type ({(int)header.ControlPacketType}) not supported.");
  81. }
  82. }
  83. private static MqttBasePacket DeserializeUnsubAck(MqttPacketReader reader)
  84. {
  85. return new MqttUnsubAckPacket
  86. {
  87. PacketIdentifier = reader.ReadUInt16()
  88. };
  89. }
  90. private static MqttBasePacket DeserializePubComp(MqttPacketReader reader)
  91. {
  92. return new MqttPubCompPacket
  93. {
  94. PacketIdentifier = reader.ReadUInt16()
  95. };
  96. }
  97. private static MqttBasePacket DeserializePubRel(MqttPacketReader reader)
  98. {
  99. return new MqttPubRelPacket
  100. {
  101. PacketIdentifier = reader.ReadUInt16()
  102. };
  103. }
  104. private static MqttBasePacket DeserializePubRec(MqttPacketReader reader)
  105. {
  106. return new MqttPubRecPacket
  107. {
  108. PacketIdentifier = reader.ReadUInt16()
  109. };
  110. }
  111. private static MqttBasePacket DeserializePubAck(MqttPacketReader reader)
  112. {
  113. return new MqttPubAckPacket
  114. {
  115. PacketIdentifier = reader.ReadUInt16()
  116. };
  117. }
  118. private static MqttBasePacket DeserializeUnsubscribe(MqttPacketReader reader)
  119. {
  120. var packet = new MqttUnsubscribePacket
  121. {
  122. PacketIdentifier = reader.ReadUInt16(),
  123. };
  124. while (!reader.EndOfRemainingData)
  125. {
  126. packet.TopicFilters.Add(reader.ReadStringWithLengthPrefix());
  127. }
  128. return packet;
  129. }
  130. private static MqttBasePacket DeserializeSubscribe(MqttPacketReader reader)
  131. {
  132. var packet = new MqttSubscribePacket
  133. {
  134. PacketIdentifier = reader.ReadUInt16()
  135. };
  136. while (!reader.EndOfRemainingData)
  137. {
  138. packet.TopicFilters.Add(new TopicFilter(
  139. reader.ReadStringWithLengthPrefix(),
  140. (MqttQualityOfServiceLevel)reader.ReadByte()));
  141. }
  142. return packet;
  143. }
  144. private static MqttBasePacket DeserializePublish(MqttPacketReader reader, MqttPacketHeader mqttPacketHeader)
  145. {
  146. var fixedHeader = new ByteReader(mqttPacketHeader.FixedHeader);
  147. var retain = fixedHeader.Read();
  148. var qualityOfServiceLevel = (MqttQualityOfServiceLevel)fixedHeader.Read(2);
  149. var dup = fixedHeader.Read();
  150. var topic = reader.ReadStringWithLengthPrefix();
  151. ushort packetIdentifier = 0;
  152. if (qualityOfServiceLevel > MqttQualityOfServiceLevel.AtMostOnce)
  153. {
  154. packetIdentifier = reader.ReadUInt16();
  155. }
  156. var packet = new MqttPublishPacket
  157. {
  158. Retain = retain,
  159. QualityOfServiceLevel = qualityOfServiceLevel,
  160. Dup = dup,
  161. Topic = topic,
  162. Payload = reader.ReadRemainingData(),
  163. PacketIdentifier = packetIdentifier
  164. };
  165. return packet;
  166. }
  167. private static MqttBasePacket DeserializeConnect(MqttPacketReader reader)
  168. {
  169. reader.ReadBytes(2); // Skip 2 bytes
  170. MqttProtocolVersion protocolVersion;
  171. var protocolName = reader.ReadBytes(4);
  172. if (protocolName.SequenceEqual(ProtocolVersionV310Name))
  173. {
  174. reader.ReadBytes(2);
  175. protocolVersion = MqttProtocolVersion.V310;
  176. }
  177. else if (protocolName.SequenceEqual(ProtocolVersionV311Name))
  178. {
  179. protocolVersion = MqttProtocolVersion.V311;
  180. }
  181. else
  182. {
  183. throw new MqttProtocolViolationException("Protocol name is not supported.");
  184. }
  185. reader.ReadByte(); // Skip protocol level
  186. var connectFlags = reader.ReadByte();
  187. var connectFlagsReader = new ByteReader(connectFlags);
  188. connectFlagsReader.Read(); // Reserved.
  189. var packet = new MqttConnectPacket
  190. {
  191. ProtocolVersion = protocolVersion,
  192. CleanSession = connectFlagsReader.Read()
  193. };
  194. var willFlag = connectFlagsReader.Read();
  195. var willQoS = connectFlagsReader.Read(2);
  196. var willRetain = connectFlagsReader.Read();
  197. var passwordFlag = connectFlagsReader.Read();
  198. var usernameFlag = connectFlagsReader.Read();
  199. packet.KeepAlivePeriod = reader.ReadUInt16();
  200. packet.ClientId = reader.ReadStringWithLengthPrefix();
  201. if (willFlag)
  202. {
  203. packet.WillMessage = new MqttApplicationMessage(
  204. reader.ReadStringWithLengthPrefix(),
  205. reader.ReadWithLengthPrefix(),
  206. (MqttQualityOfServiceLevel)willQoS,
  207. willRetain);
  208. }
  209. if (usernameFlag)
  210. {
  211. packet.Username = reader.ReadStringWithLengthPrefix();
  212. }
  213. if (passwordFlag)
  214. {
  215. packet.Password = reader.ReadStringWithLengthPrefix();
  216. }
  217. ValidateConnectPacket(packet);
  218. return packet;
  219. }
  220. private static MqttBasePacket DeserializeSubAck(MqttPacketReader reader)
  221. {
  222. var packet = new MqttSubAckPacket
  223. {
  224. PacketIdentifier = reader.ReadUInt16()
  225. };
  226. while (!reader.EndOfRemainingData)
  227. {
  228. packet.SubscribeReturnCodes.Add((MqttSubscribeReturnCode)reader.ReadByte());
  229. }
  230. return packet;
  231. }
  232. private static MqttBasePacket DeserializeConnAck(MqttPacketReader reader)
  233. {
  234. var variableHeader1 = reader.ReadByte();
  235. var variableHeader2 = reader.ReadByte();
  236. var packet = new MqttConnAckPacket
  237. {
  238. IsSessionPresent = new ByteReader(variableHeader1).Read(),
  239. ConnectReturnCode = (MqttConnectReturnCode)variableHeader2
  240. };
  241. return packet;
  242. }
  243. private static void ValidateConnectPacket(MqttConnectPacket packet)
  244. {
  245. if (packet == null) throw new ArgumentNullException(nameof(packet));
  246. if (string.IsNullOrEmpty(packet.ClientId) && !packet.CleanSession)
  247. {
  248. throw new MqttProtocolViolationException("CleanSession must be set if ClientId is empty [MQTT-3.1.3-7].");
  249. }
  250. }
  251. private static void ValidatePublishPacket(MqttPublishPacket packet)
  252. {
  253. if (packet == null) throw new ArgumentNullException(nameof(packet));
  254. if (packet.QualityOfServiceLevel == 0 && packet.Dup)
  255. {
  256. throw new MqttProtocolViolationException("Dup flag must be false for QoS 0 packets [MQTT-3.3.1-2].");
  257. }
  258. }
  259. private byte Serialize(MqttConnectPacket packet, MqttPacketWriter writer)
  260. {
  261. ValidateConnectPacket(packet);
  262. // Write variable header
  263. writer.Write(0x00, 0x04); // 3.1.2.1 Protocol Name
  264. if (ProtocolVersion == MqttProtocolVersion.V311)
  265. {
  266. writer.Write(ProtocolVersionV311Name);
  267. writer.Write(0x04); // 3.1.2.2 Protocol Level (4)
  268. }
  269. else
  270. {
  271. writer.Write(ProtocolVersionV310Name);
  272. writer.Write(0x64, 0x70, 0x03); // Protocol Level (0x03)
  273. }
  274. var connectFlags = new ByteWriter(); // 3.1.2.3 Connect Flags
  275. connectFlags.Write(false); // Reserved
  276. connectFlags.Write(packet.CleanSession);
  277. connectFlags.Write(packet.WillMessage != null);
  278. if (packet.WillMessage != null)
  279. {
  280. connectFlags.Write((int)packet.WillMessage.QualityOfServiceLevel, 2);
  281. connectFlags.Write(packet.WillMessage.Retain);
  282. }
  283. else
  284. {
  285. connectFlags.Write(0, 2);
  286. connectFlags.Write(false);
  287. }
  288. connectFlags.Write(packet.Password != null);
  289. connectFlags.Write(packet.Username != null);
  290. writer.Write(connectFlags);
  291. writer.Write(packet.KeepAlivePeriod);
  292. writer.WriteWithLengthPrefix(packet.ClientId);
  293. if (packet.WillMessage != null)
  294. {
  295. writer.WriteWithLengthPrefix(packet.WillMessage.Topic);
  296. writer.WriteWithLengthPrefix(packet.WillMessage.Payload);
  297. }
  298. if (packet.Username != null)
  299. {
  300. writer.WriteWithLengthPrefix(packet.Username);
  301. }
  302. if (packet.Password != null)
  303. {
  304. writer.WriteWithLengthPrefix(packet.Password);
  305. }
  306. return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.Connect);
  307. }
  308. private byte Serialize(MqttConnAckPacket packet, MqttPacketWriter writer)
  309. {
  310. var connectAcknowledgeFlags = new ByteWriter();
  311. if (ProtocolVersion == MqttProtocolVersion.V311)
  312. {
  313. connectAcknowledgeFlags.Write(packet.IsSessionPresent);
  314. }
  315. writer.Write(connectAcknowledgeFlags);
  316. writer.Write((byte)packet.ConnectReturnCode);
  317. return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.ConnAck);
  318. }
  319. private static byte Serialize(MqttPubRelPacket packet, MqttPacketWriter writer)
  320. {
  321. writer.Write(packet.PacketIdentifier);
  322. return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubRel, 0x02);
  323. }
  324. private static byte Serialize(MqttPublishPacket packet, MqttPacketWriter writer)
  325. {
  326. ValidatePublishPacket(packet);
  327. writer.WriteWithLengthPrefix(packet.Topic);
  328. if (packet.QualityOfServiceLevel > MqttQualityOfServiceLevel.AtMostOnce)
  329. {
  330. writer.Write(packet.PacketIdentifier);
  331. }
  332. else
  333. {
  334. if (packet.PacketIdentifier > 0)
  335. {
  336. throw new MqttProtocolViolationException("Packet identifier must be empty if QoS == 0 [MQTT-2.3.1-5].");
  337. }
  338. }
  339. if (packet.Payload?.Length > 0)
  340. {
  341. writer.Write(packet.Payload);
  342. }
  343. byte fixedHeader = 0;
  344. if (packet.Retain)
  345. {
  346. fixedHeader |= 0x01;
  347. }
  348. fixedHeader |= (byte)((byte)packet.QualityOfServiceLevel << 1);
  349. if (packet.Dup)
  350. {
  351. fixedHeader |= 0x08;
  352. }
  353. return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.Publish, fixedHeader);
  354. }
  355. private static byte Serialize(MqttPubAckPacket packet, MqttPacketWriter writer)
  356. {
  357. writer.Write(packet.PacketIdentifier);
  358. return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubAck);
  359. }
  360. private static byte Serialize(MqttPubRecPacket packet, MqttPacketWriter writer)
  361. {
  362. writer.Write(packet.PacketIdentifier);
  363. return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubRec);
  364. }
  365. private static byte Serialize(MqttPubCompPacket packet, MqttPacketWriter writer)
  366. {
  367. writer.Write(packet.PacketIdentifier);
  368. return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubComp);
  369. }
  370. private static byte Serialize(MqttSubscribePacket packet, MqttPacketWriter writer)
  371. {
  372. if (!packet.TopicFilters.Any()) throw new MqttProtocolViolationException("At least one topic filter must be set [MQTT-3.8.3-3].");
  373. writer.Write(packet.PacketIdentifier);
  374. if (packet.TopicFilters?.Count > 0)
  375. {
  376. foreach (var topicFilter in packet.TopicFilters)
  377. {
  378. writer.WriteWithLengthPrefix(topicFilter.Topic);
  379. writer.Write((byte)topicFilter.QualityOfServiceLevel);
  380. }
  381. }
  382. return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.Subscribe, 0x02);
  383. }
  384. private static byte Serialize(MqttSubAckPacket packet, MqttPacketWriter writer)
  385. {
  386. writer.Write(packet.PacketIdentifier);
  387. if (packet.SubscribeReturnCodes?.Any() == true)
  388. {
  389. foreach (var packetSubscribeReturnCode in packet.SubscribeReturnCodes)
  390. {
  391. writer.Write((byte)packetSubscribeReturnCode);
  392. }
  393. }
  394. return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.SubAck);
  395. }
  396. private static byte Serialize(MqttUnsubscribePacket packet, MqttPacketWriter writer)
  397. {
  398. if (!packet.TopicFilters.Any()) throw new MqttProtocolViolationException("At least one topic filter must be set [MQTT-3.10.3-2].");
  399. writer.Write(packet.PacketIdentifier);
  400. if (packet.TopicFilters?.Any() == true)
  401. {
  402. foreach (var topicFilter in packet.TopicFilters)
  403. {
  404. writer.WriteWithLengthPrefix(topicFilter);
  405. }
  406. }
  407. return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.Unsubscibe, 0x02);
  408. }
  409. private static byte Serialize(IMqttPacketWithIdentifier packet, BinaryWriter writer)
  410. {
  411. writer.Write(packet.PacketIdentifier);
  412. return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.UnsubAck);
  413. }
  414. private static byte SerializeEmptyPacket(MqttControlPacketType type)
  415. {
  416. return MqttPacketWriter.BuildFixedHeader(type);
  417. }
  418. }
  419. }