You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

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