-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f896c4c
commit af54f0b
Showing
13 changed files
with
268 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
require "spec" | ||
require "socket" | ||
require "./spec_helper" | ||
require "mqtt-protocol" | ||
require "../src/lavinmq/mqtt/connection_factory" | ||
|
||
|
||
def setup_connection(s, pass) | ||
left, right = UNIXSocket.pair | ||
io = MQTT::Protocol::IO.new(left) | ||
s.users.create("usr", "pass", [LavinMQ::Tag::Administrator]) | ||
MQTT::Protocol::Connect.new("abc", false, 60u16, "usr", pass.to_slice, nil).to_io(io) | ||
connection_factory = LavinMQ::MQTT::ConnectionFactory.new(right, | ||
LavinMQ::ConnectionInfo.local, | ||
s.users, | ||
s.vhosts["/"]) | ||
{ connection_factory.start, io } | ||
end | ||
|
||
describe LavinMQ do | ||
src = "127.0.0.1" | ||
dst = "127.0.0.1" | ||
|
||
it "MQTT connection should pass authentication" do | ||
with_amqp_server do |s| | ||
client, io = setup_connection(s, "pass") | ||
client.should be_a(LavinMQ::MQTT::Client) | ||
# client.close | ||
MQTT::Protocol::Disconnect.new.to_io(io) | ||
end | ||
end | ||
|
||
it "unauthorized MQTT connection should not pass authentication" do | ||
with_amqp_server do |s| | ||
client, io = setup_connection(s, "pa&ss") | ||
client.should_not be_a(LavinMQ::MQTT::Client) | ||
# client.close | ||
MQTT::Protocol::Disconnect.new.to_io(io) | ||
end | ||
end | ||
|
||
it "should handle a Ping" do | ||
with_amqp_server do |s| | ||
client, io = setup_connection(s, "pass") | ||
client.should be_a(LavinMQ::MQTT::Client) | ||
MQTT::Protocol::PingReq.new.to_io(io) | ||
MQTT::Protocol::Packet.from_io(io).should be_a(MQTT::Protocol::Connack) | ||
MQTT::Protocol::Packet.from_io(io).should be_a(MQTT::Protocol::PingResp) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
require "openssl" | ||
require "socket" | ||
require "../client" | ||
require "../error" | ||
|
||
module LavinMQ | ||
module MQTT | ||
class Client < LavinMQ::Client | ||
include Stats | ||
include SortableJSON | ||
|
||
getter vhost, channels, log, name, user | ||
Log = ::Log.for "MQTT.client" | ||
rate_stats({"send_oct", "recv_oct"}) | ||
|
||
def initialize(@socket : ::IO, | ||
@connection_info : ConnectionInfo, | ||
@vhost : VHost, | ||
@user : User) | ||
@io = MQTT::IO.new(@socket) | ||
@lock = Mutex.new | ||
@remote_address = @connection_info.src | ||
@local_address = @connection_info.dst | ||
@metadata = ::Log::Metadata.new(nil, {vhost: @vhost.name, address: @remote_address.to_s}) | ||
@log = Logger.new(Log, @metadata) | ||
@channels = Hash(UInt16, Client::Channel).new | ||
@vhost.add_connection(self) | ||
spawn read_loop | ||
connection_name = "#{@remote_address} -> #{@local_address}" | ||
@name = "#{@remote_address} -> #{@local_address}" | ||
end | ||
|
||
private def read_loop | ||
loop do | ||
Log.trace { "waiting for packet" } | ||
packet = read_and_handle_packet | ||
# The disconnect packet has been handled and the socket has been closed. | ||
# If we dont breakt the loop here we'll get a IO/Error on next read. | ||
break if packet.is_a?(MQTT::Disconnect) | ||
end | ||
rescue ex : MQTT::Error::Connect | ||
Log.warn { "Connect error #{ex.inspect}" } | ||
ensure | ||
@socket.close | ||
@vhost.rm_connection(self) | ||
end | ||
|
||
def read_and_handle_packet | ||
packet : MQTT::Packet = MQTT::Packet.from_io(@io) | ||
Log.info { "recv #{packet.inspect}" } | ||
|
||
case packet | ||
when MQTT::Publish then pp "publish" | ||
when MQTT::PubAck then pp "puback" | ||
when MQTT::Subscribe then pp "subscribe" | ||
when MQTT::Unsubscribe then pp "unsubscribe" | ||
when MQTT::PingReq then receive_pingreq(packet) | ||
when MQTT::Disconnect then return packet | ||
else raise "invalid packet type for client to send" | ||
end | ||
packet | ||
end | ||
|
||
private def send(packet) | ||
@lock.synchronize do | ||
packet.to_io(@io) | ||
@socket.flush | ||
end | ||
# @broker.increment_bytes_sent(packet.bytesize) | ||
# @broker.increment_messages_sent | ||
# @broker.increment_publish_sent if packet.is_a?(MQTT::Protocol::Publish) | ||
end | ||
|
||
def receive_pingreq(packet : MQTT::PingReq) | ||
send(MQTT::PingResp.new) | ||
end | ||
|
||
def details_tuple | ||
{ | ||
vhost: @vhost.name, | ||
user: @user.name, | ||
protocol: "MQTT", | ||
}.merge(stats_details) | ||
end | ||
|
||
def update_rates | ||
end | ||
|
||
def close(reason) | ||
end | ||
|
||
def force_close | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
require "socket" | ||
require "./protocol" | ||
require "log" | ||
require "./client" | ||
require "../vhost" | ||
require "../user" | ||
|
||
module LavinMQ | ||
module MQTT | ||
class ConnectionFactory | ||
def initialize(@socket : ::IO, | ||
@connection_info : ConnectionInfo, | ||
@users : UserStore, | ||
@vhost : VHost) | ||
end | ||
|
||
def start | ||
io = ::MQTT::Protocol::IO.new(@socket) | ||
if packet = MQTT::Packet.from_io(@socket).as?(MQTT::Connect) | ||
Log.trace { "recv #{packet.inspect}" } | ||
if user = authenticate(io, packet, @users) | ||
::MQTT::Protocol::Connack.new(false, ::MQTT::Protocol::Connack::ReturnCode::Accepted).to_io(io) | ||
io.flush | ||
return LavinMQ::MQTT::Client.new(@socket, @connection_info, @vhost, user) | ||
end | ||
end | ||
rescue ex | ||
Log.warn { "Recieved the wrong packet" } | ||
@socket.close | ||
end | ||
|
||
def authenticate(io, packet, users) | ||
return nil unless (username = packet.username) && (password = packet.password) | ||
user = users[username]? | ||
return user if user && user.password && user.password.not_nil!.verify(String.new(password)) | ||
#probably not good to differentiate between user not found and wrong password | ||
if user.nil? | ||
Log.warn { "User \"#{username}\" not found" } | ||
else | ||
Log.warn { "Authentication failure for user \"#{username}\"" } | ||
end | ||
::MQTT::Protocol::Connack.new(false, ::MQTT::Protocol::Connack::ReturnCode::NotAuthorized).to_io(io) | ||
nil | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
require "mqtt-protocol" | ||
|
||
module LavinMQ | ||
module MQTT | ||
include ::MQTT::Protocol | ||
end | ||
end |
Oops, something went wrong.