25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

MqttPacketSerializer.cs 19 KiB

7 년 전
7 년 전
7 년 전
7 년 전
7 년 전
7 년 전
7 년 전
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  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. {
  205. Topic = reader.ReadStringWithLengthPrefix(),
  206. Payload = reader.ReadWithLengthPrefix(),
  207. QualityOfServiceLevel = (MqttQualityOfServiceLevel)willQoS,
  208. Retain = willRetain
  209. };
  210. }
  211. if (usernameFlag)
  212. {
  213. packet.Username = reader.ReadStringWithLengthPrefix();
  214. }
  215. if (passwordFlag)
  216. {
  217. packet.Password = reader.ReadStringWithLengthPrefix();
  218. }
  219. ValidateConnectPacket(packet);
  220. return packet;
  221. }
  222. private static MqttBasePacket DeserializeSubAck(MqttPacketReader reader)
  223. {
  224. var packet = new MqttSubAckPacket
  225. {
  226. PacketIdentifier = reader.ReadUInt16()
  227. };
  228. while (!reader.EndOfRemainingData)
  229. {
  230. packet.SubscribeReturnCodes.Add((MqttSubscribeReturnCode)reader.ReadByte());
  231. }
  232. return packet;
  233. }
  234. private static MqttBasePacket DeserializeConnAck(MqttPacketReader reader)
  235. {
  236. var variableHeader1 = reader.ReadByte();
  237. var variableHeader2 = reader.ReadByte();
  238. var packet = new MqttConnAckPacket
  239. {
  240. IsSessionPresent = new ByteReader(variableHeader1).Read(),
  241. ConnectReturnCode = (MqttConnectReturnCode)variableHeader2
  242. };
  243. return packet;
  244. }
  245. private static void ValidateConnectPacket(MqttConnectPacket packet)
  246. {
  247. if (packet == null) throw new ArgumentNullException(nameof(packet));
  248. if (string.IsNullOrEmpty(packet.ClientId) && !packet.CleanSession)
  249. {
  250. throw new MqttProtocolViolationException("CleanSession must be set if ClientId is empty [MQTT-3.1.3-7].");
  251. }
  252. }
  253. private static void ValidatePublishPacket(MqttPublishPacket packet)
  254. {
  255. if (packet == null) throw new ArgumentNullException(nameof(packet));
  256. if (packet.QualityOfServiceLevel == 0 && packet.Dup)
  257. {
  258. throw new MqttProtocolViolationException("Dup flag must be false for QoS 0 packets [MQTT-3.3.1-2].");
  259. }
  260. }
  261. private byte Serialize(MqttConnectPacket packet, MqttPacketWriter writer)
  262. {
  263. ValidateConnectPacket(packet);
  264. // Write variable header
  265. writer.Write(0x00, 0x04); // 3.1.2.1 Protocol Name
  266. if (ProtocolVersion == MqttProtocolVersion.V311)
  267. {
  268. writer.Write(ProtocolVersionV311Name);
  269. writer.Write(0x04); // 3.1.2.2 Protocol Level (4)
  270. }
  271. else
  272. {
  273. writer.Write(ProtocolVersionV310Name);
  274. writer.Write(0x64, 0x70, 0x03); // Protocol Level (0x03)
  275. }
  276. var connectFlags = new ByteWriter(); // 3.1.2.3 Connect Flags
  277. connectFlags.Write(false); // Reserved
  278. connectFlags.Write(packet.CleanSession);
  279. connectFlags.Write(packet.WillMessage != null);
  280. if (packet.WillMessage != null)
  281. {
  282. connectFlags.Write((int)packet.WillMessage.QualityOfServiceLevel, 2);
  283. connectFlags.Write(packet.WillMessage.Retain);
  284. }
  285. else
  286. {
  287. connectFlags.Write(0, 2);
  288. connectFlags.Write(false);
  289. }
  290. connectFlags.Write(packet.Password != null);
  291. connectFlags.Write(packet.Username != null);
  292. writer.Write(connectFlags);
  293. writer.Write(packet.KeepAlivePeriod);
  294. writer.WriteWithLengthPrefix(packet.ClientId);
  295. if (packet.WillMessage != null)
  296. {
  297. writer.WriteWithLengthPrefix(packet.WillMessage.Topic);
  298. writer.WriteWithLengthPrefix(packet.WillMessage.Payload);
  299. }
  300. if (packet.Username != null)
  301. {
  302. writer.WriteWithLengthPrefix(packet.Username);
  303. }
  304. if (packet.Password != null)
  305. {
  306. writer.WriteWithLengthPrefix(packet.Password);
  307. }
  308. return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.Connect);
  309. }
  310. private byte Serialize(MqttConnAckPacket packet, MqttPacketWriter writer)
  311. {
  312. var connectAcknowledgeFlags = new ByteWriter();
  313. if (ProtocolVersion == MqttProtocolVersion.V311)
  314. {
  315. connectAcknowledgeFlags.Write(packet.IsSessionPresent);
  316. }
  317. writer.Write(connectAcknowledgeFlags);
  318. writer.Write((byte)packet.ConnectReturnCode);
  319. return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.ConnAck);
  320. }
  321. private static byte Serialize(MqttPubRelPacket packet, MqttPacketWriter writer)
  322. {
  323. writer.Write(packet.PacketIdentifier);
  324. return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubRel, 0x02);
  325. }
  326. private static byte Serialize(MqttPublishPacket packet, MqttPacketWriter writer)
  327. {
  328. ValidatePublishPacket(packet);
  329. writer.WriteWithLengthPrefix(packet.Topic);
  330. if (packet.QualityOfServiceLevel > MqttQualityOfServiceLevel.AtMostOnce)
  331. {
  332. writer.Write(packet.PacketIdentifier);
  333. }
  334. else
  335. {
  336. if (packet.PacketIdentifier > 0)
  337. {
  338. throw new MqttProtocolViolationException("Packet identifier must be empty if QoS == 0 [MQTT-2.3.1-5].");
  339. }
  340. }
  341. if (packet.Payload?.Length > 0)
  342. {
  343. writer.Write(packet.Payload);
  344. }
  345. byte fixedHeader = 0;
  346. if (packet.Retain)
  347. {
  348. fixedHeader |= 0x01;
  349. }
  350. fixedHeader |= (byte)((byte)packet.QualityOfServiceLevel << 1);
  351. if (packet.Dup)
  352. {
  353. fixedHeader |= 0x08;
  354. }
  355. return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.Publish, fixedHeader);
  356. }
  357. private static byte Serialize(MqttPubAckPacket packet, MqttPacketWriter writer)
  358. {
  359. writer.Write(packet.PacketIdentifier);
  360. return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubAck);
  361. }
  362. private static byte Serialize(MqttPubRecPacket packet, MqttPacketWriter writer)
  363. {
  364. writer.Write(packet.PacketIdentifier);
  365. return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubRec);
  366. }
  367. private static byte Serialize(MqttPubCompPacket packet, MqttPacketWriter writer)
  368. {
  369. writer.Write(packet.PacketIdentifier);
  370. return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubComp);
  371. }
  372. private static byte Serialize(MqttSubscribePacket packet, MqttPacketWriter writer)
  373. {
  374. if (!packet.TopicFilters.Any()) throw new MqttProtocolViolationException("At least one topic filter must be set [MQTT-3.8.3-3].");
  375. writer.Write(packet.PacketIdentifier);
  376. if (packet.TopicFilters?.Count > 0)
  377. {
  378. foreach (var topicFilter in packet.TopicFilters)
  379. {
  380. writer.WriteWithLengthPrefix(topicFilter.Topic);
  381. writer.Write((byte)topicFilter.QualityOfServiceLevel);
  382. }
  383. }
  384. return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.Subscribe, 0x02);
  385. }
  386. private static byte Serialize(MqttSubAckPacket packet, MqttPacketWriter writer)
  387. {
  388. writer.Write(packet.PacketIdentifier);
  389. if (packet.SubscribeReturnCodes?.Any() == true)
  390. {
  391. foreach (var packetSubscribeReturnCode in packet.SubscribeReturnCodes)
  392. {
  393. writer.Write((byte)packetSubscribeReturnCode);
  394. }
  395. }
  396. return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.SubAck);
  397. }
  398. private static byte Serialize(MqttUnsubscribePacket packet, MqttPacketWriter writer)
  399. {
  400. if (!packet.TopicFilters.Any()) throw new MqttProtocolViolationException("At least one topic filter must be set [MQTT-3.10.3-2].");
  401. writer.Write(packet.PacketIdentifier);
  402. if (packet.TopicFilters?.Any() == true)
  403. {
  404. foreach (var topicFilter in packet.TopicFilters)
  405. {
  406. writer.WriteWithLengthPrefix(topicFilter);
  407. }
  408. }
  409. return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.Unsubscibe, 0x02);
  410. }
  411. private static byte Serialize(IMqttPacketWithIdentifier packet, BinaryWriter writer)
  412. {
  413. writer.Write(packet.PacketIdentifier);
  414. return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.UnsubAck);
  415. }
  416. private static byte SerializeEmptyPacket(MqttControlPacketType type)
  417. {
  418. return MqttPacketWriter.BuildFixedHeader(type);
  419. }
  420. }
  421. }