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.
 
 
 
 

612 lines
20 KiB

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