Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 

611 linhas
22 KiB

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