Mercurial > prosody-modules
comparison mod_pubsub_mqtt/mqtt.lib.lua @ 5833:58df53eefa28
mod_pubsub_mqtt: Update to MQTT 3.1.1
| author | Matthew Wild <mwild1@gmail.com> |
|---|---|
| date | Wed, 07 Feb 2024 11:57:30 +0000 |
| parents | d2a84e6aed2b |
| children | ef625180a869 |
comparison
equal
deleted
inserted
replaced
| 5832:5afc8273c5ef | 5833:58df53eefa28 |
|---|---|
| 1 local bit = require "bit"; | 1 local bit = require "util.bitcompat"; |
| 2 | 2 |
| 3 local stream_mt = {}; | 3 local stream_mt = {}; |
| 4 stream_mt.__index = stream_mt; | 4 stream_mt.__index = stream_mt; |
| 5 | 5 |
| 6 function stream_mt:read_bytes(n_bytes) | 6 function stream_mt:read_bytes(n_bytes) |
| 27 local len1, len2 = self:read_bytes(2):byte(1,2); | 27 local len1, len2 = self:read_bytes(2):byte(1,2); |
| 28 local len = bit.lshift(len1, 8) + len2; | 28 local len = bit.lshift(len1, 8) + len2; |
| 29 return self:read_bytes(len), len+2; | 29 return self:read_bytes(len), len+2; |
| 30 end | 30 end |
| 31 | 31 |
| 32 function stream_mt:read_word() | |
| 33 local len1, len2 = self:read_bytes(2):byte(1,2); | |
| 34 local result = bit.lshift(len1, 8) + len2; | |
| 35 module:log("debug", "read_word(%02x, %02x) = %04x (%d)", len1, len2, result, result); | |
| 36 return result; | |
| 37 end | |
| 38 | |
| 39 local function hasbit(byte, n_bit) | |
| 40 return bit.band(byte, 2^n_bit) ~= 0; | |
| 41 end | |
| 42 | |
| 43 local function encode_string(str) | |
| 44 return string.char(bit.band(#str, 0xff00), bit.band(#str, 0x00ff))..str; | |
| 45 end | |
| 46 | |
| 32 local packet_type_codes = { | 47 local packet_type_codes = { |
| 33 "connect", "connack", | 48 "connect", "connack", |
| 34 "publish", "puback", "pubrec", "pubrel", "pubcomp", | 49 "publish", "puback", "pubrec", "pubrel", "pubcomp", |
| 35 "subscribe", "subak", "unsubscribe", "unsuback", | 50 "subscribe", "suback", "unsubscribe", "unsuback", |
| 36 "pingreq", "pingresp", | 51 "pingreq", "pingresp", |
| 37 "disconnect" | 52 "disconnect" |
| 38 }; | 53 }; |
| 39 | 54 |
| 40 function stream_mt:read_packet() | 55 function stream_mt:read_packet() |
| 57 if self:read_string() ~= "MQTT" then | 72 if self:read_string() ~= "MQTT" then |
| 58 module:log("warn", "Unexpected packet signature!"); | 73 module:log("warn", "Unexpected packet signature!"); |
| 59 packet.type = nil; -- Invalid packet | 74 packet.type = nil; -- Invalid packet |
| 60 else | 75 else |
| 61 packet.version = self:read_bytes(1):byte(); | 76 packet.version = self:read_bytes(1):byte(); |
| 62 packet.connect_flags = self:read_bytes(1):byte(); | 77 module:log("debug", "ver: %02x", packet.version); |
| 63 packet.keepalive_timer = self:read_bytes(1):byte(); | 78 if packet.version ~= 0x04 then |
| 79 module:log("warn", "MQTT version mismatch (got %02x, we support %02x", packet.version, 0x04); | |
| 80 end | |
| 81 local flags = self:read_bytes(1):byte(); | |
| 82 module:log("debug", "flags: %02x", flags); | |
| 83 packet.keepalive_timer = self:read_bytes(2):byte(); | |
| 84 module:log("debug", "keepalive: %d", packet.keepalive_timer); | |
| 85 packet.connect_flags = {}; | |
| 64 length = length - 11; | 86 length = length - 11; |
| 87 packet.connect_flags = { | |
| 88 clean_session = hasbit(flags, 1); | |
| 89 will = hasbit(flags, 2); | |
| 90 will_qos = bit.band(bit.rshift(flags, 2), 0x02); | |
| 91 will_retain = hasbit(flags, 5); | |
| 92 user_name = hasbit(flags, 7); | |
| 93 password = hasbit(flags, 6); | |
| 94 }; | |
| 95 module:log("debug", "%s", require "util.serialization".serialize(packet.connect_flags, "debug")); | |
| 96 module:log("debug", "Reading client_id..."); | |
| 97 packet.client_id = self:read_string(); | |
| 98 if packet.connect_flags.will then | |
| 99 module:log("debug", "Reading will..."); | |
| 100 packet.will = { | |
| 101 topic = self:read_string(); | |
| 102 message = self:read_string(); | |
| 103 qos = packet.connect_flags.will_qos; | |
| 104 retain = packet.connect_flags.will_retain; | |
| 105 }; | |
| 106 end | |
| 107 if packet.connect_flags.user_name then | |
| 108 module:log("debug", "Reading username..."); | |
| 109 packet.username = self:read_string(); | |
| 110 end | |
| 111 if packet.connect_flags.password then | |
| 112 module:log("debug", "Reading password..."); | |
| 113 packet.password = self:read_string(); | |
| 114 end | |
| 115 module:log("debug", "Done parsing connect!"); | |
| 116 length = 0; -- No payload left | |
| 65 end | 117 end |
| 66 elseif packet.type == "publish" then | 118 elseif packet.type == "publish" then |
| 67 packet.topic = self:read_string(); | 119 packet.topic = self:read_string(); |
| 68 length = length - (#packet.topic+2); | 120 length = length - (#packet.topic+2); |
| 69 if packet.qos == 1 or packet.qos == 2 then | 121 if packet.qos == 1 or packet.qos == 2 then |
| 85 packet.topics = topics; | 137 packet.topics = topics; |
| 86 end | 138 end |
| 87 if length > 0 then | 139 if length > 0 then |
| 88 packet.data = self:read_bytes(length); | 140 packet.data = self:read_bytes(length); |
| 89 end | 141 end |
| 142 module:log("debug", "MQTT packet complete!"); | |
| 90 return packet; | 143 return packet; |
| 91 end | 144 end |
| 92 | 145 |
| 93 local function new_parser(self) | 146 local function new_parser(self) |
| 94 return coroutine.wrap(function (data) | 147 return coroutine.wrap(function (data) |
| 100 end | 153 end |
| 101 end); | 154 end); |
| 102 end | 155 end |
| 103 | 156 |
| 104 function stream_mt:feed(data) | 157 function stream_mt:feed(data) |
| 105 module:log("debug", "Feeding %d bytes", #data); | |
| 106 local packets = {}; | 158 local packets = {}; |
| 107 local packet = self.parser(data); | 159 local packet = self.parser(data); |
| 108 while packet do | 160 while packet do |
| 109 module:log("debug", "Received packet"); | 161 module:log("debug", "Received packet"); |
| 110 table.insert(packets, packet); | 162 table.insert(packets, packet); |
| 133 if packet.type == "publish" then | 185 if packet.type == "publish" then |
| 134 local topic = packet.topic or ""; | 186 local topic = packet.topic or ""; |
| 135 packet.data = string.char(bit.band(#topic, 0xff00), bit.band(#topic, 0x00ff))..topic..packet.data; | 187 packet.data = string.char(bit.band(#topic, 0xff00), bit.band(#topic, 0x00ff))..topic..packet.data; |
| 136 elseif packet.type == "suback" then | 188 elseif packet.type == "suback" then |
| 137 local t = {}; | 189 local t = {}; |
| 138 for _, topic in ipairs(packet.topics) do | 190 for i, result_code in ipairs(packet.results) do |
| 139 table.insert(t, string.char(bit.band(#topic, 0xff00), bit.band(#topic, 0x00ff))..topic.."\000"); | 191 table.insert(t, string.char(result_code)); |
| 140 end | 192 end |
| 141 packet.data = table.concat(t); | 193 packet.data = packet.id..table.concat(t); |
| 142 end | 194 end |
| 143 | 195 |
| 144 -- Get length | 196 -- Get length |
| 145 local length = #(packet.data or ""); | 197 local length = #(packet.data or ""); |
| 146 repeat | 198 repeat |
