Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 
 

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