Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.
 
 
 
 

589 rindas
21 KiB

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