Compare commits

..

No commits in common. "e014cb2656387a3e9e5055682ccba6d2d068f3c6" and "8e34d4d144f76b79ea51f6218e472e96a1945f54" have entirely different histories.

1 changed files with 19 additions and 83 deletions

102
mqtt.lua
View File

@ -10,52 +10,32 @@ local safeRead = function (conn, n)
end end
local readVarint = function (conn, first_byte) local readVarint = function (conn, first_byte)
local b, data, err local b, err
if first_byte == nil then if first_byte == nil then
data, err = safeRead(conn, 1) b, err = safeRead(conn, 1)
if err ~= nil then
return nil, err
end
b = string.byte(data)
else else
b = first_byte b = first_byte
end end
local n, s = 0, 0 local n, s = 0, 0
while b & 0x80 == 0x80 do while err == nil and b & 0x80 == 0x80 do
if s > 21 then if s > 21 then
return nil, "number too large" return 0, "number too large"
end end
n = n + ((b & 0x7F) << s) n = n + ((b & 0x7F) << s)
s = s + 7 s = s + 7
data, err = safeRead(conn, 1) b, err = safeRead(conn, 1)
if err ~= nil then end
return nil, err
end
b = string.byte(data) if err ~= nil then
return n, err
end end
return n + (b << s), nil return n + (b << s), nil
end end
local encodeVarint = function (n)
if n > 268435455 then
return nil, "number too large"
end
local data = ""
while n > 127 do
data = data .. string.char(0x80 | n & 0x7F)
n = n >> 7
end
return data .. string.char(n), nil
end
local MqttClient = {} local MqttClient = {}
function mqtt.open (address, port) function mqtt.open (address, port)
@ -84,10 +64,6 @@ function MqttClient:new (conn)
end end
function MqttClient:handle () function MqttClient:handle ()
if not (self.is_connecting or self.is_connected) then
return "no connection"
end
local data, err = self.conn:safeRead(2) local data, err = self.conn:safeRead(2)
if err ~= nil then if err ~= nil then
return err return err
@ -135,27 +111,12 @@ function MqttClient:handle ()
self.is_connecting = false self.is_connecting = false
self.is_connected = true self.is_connected = true
elseif ptype & 0xF0 == 0x40 then -- PUBACK elseif ptype == 0x40 then -- PUBACK
-- TODO -- TODO
elseif ptype & 0xF0 == 0xD0 then -- PINGRESP elseif ptype == 0xD0 then -- PINGRESP
-- TODO
elseif ptype == 0xE0 then -- DISCONNECT
-- TODO -- TODO
elseif ptype & 0xF0 == 0xE0 then -- DISCONNECT
if ptype ~= 0xE0 then
self:disconnect(0x81)
return "malformed packet"
end
self.is_connecting = false
self.is_connected = false
if length > 0 then
reason, _ = string.unpack("B", data)
if reason ~= 0 then
return "disconnect with error"
end
end
return "disconnect"
end end
return nil return nil
@ -163,7 +124,7 @@ end
function MqttClient:connect (username, password) function MqttClient:connect (username, password)
if self.is_connecting or self.is_connected then if self.is_connecting or self.is_connected then
return "already connected" return nil
end end
local length = 13 local length = 13
@ -177,7 +138,11 @@ function MqttClient:connect (username, password)
flags = flags | 0x40 flags = flags | 0x40
end end
local data = string.char(0x10) .. encodeVarint(length) .. string.pack("> s2 B B I2 B s2", "MQTT", 5, flags, 0, 0, "") if length > 127 then
return "packet size exceeds current implementation capabilities"
end
local data = string.pack("> B B s2 B B I2 B s2", 0x10, length, "MQTT", 5, flags, 0, 0, "")
if username ~= nil then if username ~= nil then
data = data .. string.pack("> s2", username) data = data .. string.pack("> s2", username)
end end
@ -200,38 +165,9 @@ function MqttClient:connect (username, password)
return nil return nil
end end
function MqttClient:publish (topic, payload)
if not (self.is_connecting or self.is_connected) then
return "no connection"
end
if not topic or #topic == 0 then
return "topic is required"
end
if not payload then
payload = ""
end
local flags = 0
local length = 3 + #topic + #payload
local data = string.char(0x30 | flags) .. encodeVarint(length) .. string.pack("> s2 B", topic, 0) .. payload
local _, err = self.conn:write(data)
if err ~= nil then
return err
end
local _, err = self.conn:flush()
if err ~= nil then
return err
end
return nil
end
function MqttClient:disconnect (reason) function MqttClient:disconnect (reason)
if not (self.is_connecting or self.is_connected) then if not (self.is_connecting or self.is_connected) then
return "no connection" return nil
end end
if reason == nil then if reason == nil then