Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 

610 строки
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(
  179. $"Packet type ({(int)header.ControlPacketType}) not supported.");
  180. }
  181. }
  182. }
  183. private static MqttBasePacket DeserializeUnsubscribe(MqttPacketReader reader)
  184. {
  185. var packet = new MqttUnsubscribePacket
  186. {
  187. PacketIdentifier = reader.ReadUInt16(),
  188. };
  189. while (!reader.EndOfRemainingData)
  190. {
  191. packet.TopicFilters.Add(reader.ReadStringWithLengthPrefix());
  192. }
  193. return packet;
  194. }
  195. private static MqttBasePacket DeserializeSubscribe(MqttPacketReader reader)
  196. {
  197. var packet = new MqttSubscribePacket
  198. {
  199. PacketIdentifier = reader.ReadUInt16()
  200. };
  201. while (!reader.EndOfRemainingData)
  202. {
  203. packet.TopicFilters.Add(new TopicFilter(
  204. reader.ReadStringWithLengthPrefix(),
  205. (MqttQualityOfServiceLevel)reader.ReadByte()));
  206. }
  207. return packet;
  208. }
  209. private static MqttBasePacket DeserializePublish(MqttPacketReader reader, MqttPacketHeader mqttPacketHeader)
  210. {
  211. var fixedHeader = new ByteReader(mqttPacketHeader.FixedHeader);
  212. var retain = fixedHeader.Read();
  213. var qualityOfServiceLevel = (MqttQualityOfServiceLevel)fixedHeader.Read(2);
  214. var dup = fixedHeader.Read();
  215. var topic = reader.ReadStringWithLengthPrefix();
  216. ushort packetIdentifier = 0;
  217. if (qualityOfServiceLevel > MqttQualityOfServiceLevel.AtMostOnce)
  218. {
  219. packetIdentifier = reader.ReadUInt16();
  220. }
  221. var packet = new MqttPublishPacket
  222. {
  223. Retain = retain,
  224. QualityOfServiceLevel = qualityOfServiceLevel,
  225. Dup = dup,
  226. Topic = topic,
  227. Payload = reader.ReadRemainingData(),
  228. PacketIdentifier = packetIdentifier
  229. };
  230. return packet;
  231. }
  232. private static MqttBasePacket DeserializeConnect(MqttPacketReader reader)
  233. {
  234. reader.ReadBytes(2); // Skip 2 bytes
  235. MqttProtocolVersion protocolVersion;
  236. var protocolName = reader.ReadBytes(4);
  237. if (protocolName.SequenceEqual(ProtocolVersionV310Name))
  238. {
  239. reader.ReadBytes(2);
  240. protocolVersion = MqttProtocolVersion.V310;
  241. }
  242. else if (protocolName.SequenceEqual(ProtocolVersionV311Name))
  243. {
  244. protocolVersion = MqttProtocolVersion.V311;
  245. }
  246. else
  247. {
  248. throw new MqttProtocolViolationException("Protocol name is not supported.");
  249. }
  250. var protocolLevel = reader.ReadByte();
  251. var connectFlags = reader.ReadByte();
  252. var connectFlagsReader = new ByteReader(connectFlags);
  253. connectFlagsReader.Read(); // Reserved.
  254. var packet = new MqttConnectPacket
  255. {
  256. ProtocolVersion = protocolVersion,
  257. CleanSession = connectFlagsReader.Read()
  258. };
  259. var willFlag = connectFlagsReader.Read();
  260. var willQoS = connectFlagsReader.Read(2);
  261. var willRetain = connectFlagsReader.Read();
  262. var passwordFlag = connectFlagsReader.Read();
  263. var usernameFlag = connectFlagsReader.Read();
  264. packet.KeepAlivePeriod = reader.ReadUInt16();
  265. packet.ClientId = reader.ReadStringWithLengthPrefix();
  266. if (willFlag)
  267. {
  268. packet.WillMessage = new MqttApplicationMessage(
  269. reader.ReadStringWithLengthPrefix(),
  270. reader.ReadWithLengthPrefix(),
  271. (MqttQualityOfServiceLevel)willQoS,
  272. willRetain);
  273. }
  274. if (usernameFlag)
  275. {
  276. packet.Username = reader.ReadStringWithLengthPrefix();
  277. }
  278. if (passwordFlag)
  279. {
  280. packet.Password = reader.ReadStringWithLengthPrefix();
  281. }
  282. ValidateConnectPacket(packet);
  283. return packet;
  284. }
  285. private static MqttBasePacket DeserializeSubAck(MqttPacketReader reader)
  286. {
  287. var packet = new MqttSubAckPacket
  288. {
  289. PacketIdentifier = reader.ReadUInt16()
  290. };
  291. while (!reader.EndOfRemainingData)
  292. {
  293. packet.SubscribeReturnCodes.Add((MqttSubscribeReturnCode)reader.ReadByte());
  294. }
  295. return packet;
  296. }
  297. private static MqttBasePacket DeserializeConnAck(MqttPacketReader reader)
  298. {
  299. var variableHeader1 = reader.ReadByte();
  300. var variableHeader2 = reader.ReadByte();
  301. var packet = new MqttConnAckPacket
  302. {
  303. IsSessionPresent = new ByteReader(variableHeader1).Read(),
  304. ConnectReturnCode = (MqttConnectReturnCode)variableHeader2
  305. };
  306. return packet;
  307. }
  308. private static void ValidateConnectPacket(MqttConnectPacket packet)
  309. {
  310. if (string.IsNullOrEmpty(packet.ClientId) && !packet.CleanSession)
  311. {
  312. throw new MqttProtocolViolationException("CleanSession must be set if ClientId is empty [MQTT-3.1.3-7].");
  313. }
  314. }
  315. private static void ValidatePublishPacket(MqttPublishPacket packet)
  316. {
  317. if (packet.QualityOfServiceLevel == 0 && packet.Dup)
  318. {
  319. throw new MqttProtocolViolationException("Dup flag must be false for QoS 0 packets [MQTT-3.3.1-2].");
  320. }
  321. }
  322. private byte Serialize(MqttConnectPacket packet, MqttPacketWriter writer)
  323. {
  324. ValidateConnectPacket(packet);
  325. // Write variable header
  326. writer.Write(0x00, 0x04); // 3.1.2.1 Protocol Name
  327. if (ProtocolVersion == MqttProtocolVersion.V311)
  328. {
  329. writer.Write(ProtocolVersionV311Name);
  330. writer.Write(0x04); // 3.1.2.2 Protocol Level (4)
  331. }
  332. else
  333. {
  334. writer.Write(ProtocolVersionV310Name);
  335. writer.Write(0x64, 0x70, 0x03); // Protocol Level (0x03)
  336. }
  337. var connectFlags = new ByteWriter(); // 3.1.2.3 Connect Flags
  338. connectFlags.Write(false); // Reserved
  339. connectFlags.Write(packet.CleanSession);
  340. connectFlags.Write(packet.WillMessage != null);
  341. if (packet.WillMessage != null)
  342. {
  343. connectFlags.Write((int)packet.WillMessage.QualityOfServiceLevel, 2);
  344. connectFlags.Write(packet.WillMessage.Retain);
  345. }
  346. else
  347. {
  348. connectFlags.Write(0, 2);
  349. connectFlags.Write(false);
  350. }
  351. connectFlags.Write(packet.Password != null);
  352. connectFlags.Write(packet.Username != null);
  353. writer.Write(connectFlags);
  354. writer.Write(packet.KeepAlivePeriod);
  355. writer.WriteWithLengthPrefix(packet.ClientId);
  356. if (packet.WillMessage != null)
  357. {
  358. writer.WriteWithLengthPrefix(packet.WillMessage.Topic);
  359. writer.WriteWithLengthPrefix(packet.WillMessage.Payload);
  360. }
  361. if (packet.Username != null)
  362. {
  363. writer.WriteWithLengthPrefix(packet.Username);
  364. }
  365. if (packet.Password != null)
  366. {
  367. writer.WriteWithLengthPrefix(packet.Password);
  368. }
  369. return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.Connect);
  370. }
  371. private byte Serialize(MqttConnAckPacket packet, MqttPacketWriter writer)
  372. {
  373. var connectAcknowledgeFlags = new ByteWriter();
  374. if (ProtocolVersion == MqttProtocolVersion.V311)
  375. {
  376. connectAcknowledgeFlags.Write(packet.IsSessionPresent);
  377. }
  378. writer.Write(connectAcknowledgeFlags);
  379. writer.Write((byte)packet.ConnectReturnCode);
  380. return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.ConnAck);
  381. }
  382. private static byte Serialize(MqttPubRelPacket packet, MqttPacketWriter writer)
  383. {
  384. writer.Write(packet.PacketIdentifier);
  385. return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubRel, 0x02);
  386. }
  387. private static byte Serialize(MqttDisconnectPacket packet, MqttPacketWriter writer)
  388. {
  389. return SerializeEmptyPacketAsync(MqttControlPacketType.Disconnect, writer);
  390. }
  391. private static byte Serialize(MqttPingReqPacket packet, MqttPacketWriter writer)
  392. {
  393. return SerializeEmptyPacketAsync(MqttControlPacketType.PingReq, writer);
  394. }
  395. private static byte Serialize(MqttPingRespPacket packet, MqttPacketWriter writer)
  396. {
  397. return SerializeEmptyPacketAsync(MqttControlPacketType.PingResp, writer);
  398. }
  399. private static byte Serialize(MqttPublishPacket packet, MqttPacketWriter writer)
  400. {
  401. ValidatePublishPacket(packet);
  402. writer.WriteWithLengthPrefix(packet.Topic);
  403. if (packet.QualityOfServiceLevel > MqttQualityOfServiceLevel.AtMostOnce)
  404. {
  405. writer.Write(packet.PacketIdentifier);
  406. }
  407. else
  408. {
  409. if (packet.PacketIdentifier > 0)
  410. {
  411. throw new MqttProtocolViolationException("Packet identifier must be empty if QoS == 0 [MQTT-2.3.1-5].");
  412. }
  413. }
  414. if (packet.Payload?.Length > 0)
  415. {
  416. writer.Write(packet.Payload);
  417. }
  418. byte fixedHeader = 0;
  419. if (packet.Retain)
  420. {
  421. fixedHeader |= 0x01;
  422. }
  423. fixedHeader |= (byte)((byte)packet.QualityOfServiceLevel << 1);
  424. if (packet.Dup)
  425. {
  426. fixedHeader |= 0x08;
  427. }
  428. return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.Publish, fixedHeader);
  429. }
  430. private static byte Serialize(MqttPubAckPacket packet, MqttPacketWriter writer)
  431. {
  432. writer.Write(packet.PacketIdentifier);
  433. return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubAck);
  434. }
  435. private static byte Serialize(MqttPubRecPacket packet, MqttPacketWriter writer)
  436. {
  437. writer.Write(packet.PacketIdentifier);
  438. return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubRec);
  439. }
  440. private static byte Serialize(MqttPubCompPacket packet, MqttPacketWriter writer)
  441. {
  442. writer.Write(packet.PacketIdentifier);
  443. return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubComp);
  444. }
  445. private static byte Serialize(MqttSubscribePacket packet, MqttPacketWriter writer)
  446. {
  447. if (!packet.TopicFilters.Any()) throw new MqttProtocolViolationException("At least one topic filter must be set [MQTT-3.8.3-3].");
  448. writer.Write(packet.PacketIdentifier);
  449. if (packet.TopicFilters?.Count > 0)
  450. {
  451. foreach (var topicFilter in packet.TopicFilters)
  452. {
  453. writer.WriteWithLengthPrefix(topicFilter.Topic);
  454. writer.Write((byte)topicFilter.QualityOfServiceLevel);
  455. }
  456. }
  457. return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.Subscribe, 0x02);
  458. }
  459. private static byte Serialize(MqttSubAckPacket packet, MqttPacketWriter writer)
  460. {
  461. writer.Write(packet.PacketIdentifier);
  462. if (packet.SubscribeReturnCodes?.Any() == true)
  463. {
  464. foreach (var packetSubscribeReturnCode in packet.SubscribeReturnCodes)
  465. {
  466. writer.Write((byte)packetSubscribeReturnCode);
  467. }
  468. }
  469. return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.SubAck);
  470. }
  471. private static byte Serialize(MqttUnsubscribePacket packet, MqttPacketWriter writer)
  472. {
  473. if (!packet.TopicFilters.Any()) throw new MqttProtocolViolationException("At least one topic filter must be set [MQTT-3.10.3-2].");
  474. writer.Write(packet.PacketIdentifier);
  475. if (packet.TopicFilters?.Any() == true)
  476. {
  477. foreach (var topicFilter in packet.TopicFilters)
  478. {
  479. writer.WriteWithLengthPrefix(topicFilter);
  480. }
  481. }
  482. return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.Unsubscibe, 0x02);
  483. }
  484. private static byte Serialize(MqttUnsubAckPacket packet, MqttPacketWriter writer)
  485. {
  486. writer.Write(packet.PacketIdentifier);
  487. return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.UnsubAck);
  488. }
  489. private static byte SerializeEmptyPacketAsync(MqttControlPacketType type, MqttPacketWriter writer)
  490. {
  491. return MqttPacketWriter.BuildFixedHeader(type);
  492. }
  493. }
  494. }