Skip to content

Commit

Permalink
Support nonblocking socket read before select for MRI 1.9.3+ only
Browse files Browse the repository at this point in the history
  • Loading branch information
camlow325 committed Nov 15, 2017
1 parent b6cda35 commit d23a669
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 8 deletions.
24 changes: 21 additions & 3 deletions lib/mqtt/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,14 @@ def initialize(*args)
@read_thread = nil
@write_semaphore = Mutex.new
@pubacks_semaphore = Mutex.new

@wait_for_read_func = method(
if OpenSSL::SSL::SSLSocket.method_defined?(:read_nonblock)
:nonblocking_read_before_select
else
:select_without_nonblocking_read
end
)
end

# Get the OpenSSL context, that is used if SSL/TLS is enabled
Expand Down Expand Up @@ -438,9 +446,12 @@ def unsubscribe(*topics)

private

# Try to read a packet from the server
# Also sends keep-alive ping packets.
def receive_packet
def select_without_nonblocking_read
# Poll socket - is there data waiting?
[nil, !IO.select([@socket], [], [], SELECT_TIMEOUT).nil?]
end

def nonblocking_read_before_select
first_byte_in_packet = nil
data_available_to_read = false
begin
Expand All @@ -456,6 +467,13 @@ def receive_packet
[@socket], [], [], SELECT_TIMEOUT
).nil?
end
[first_byte_in_packet, data_available_to_read]
end

# Try to read a packet from the server
# Also sends keep-alive ping packets.
def receive_packet
first_byte_in_packet, data_available_to_read = @wait_for_read_func.call
if data_available_to_read
# Yes - read in the packet
packet = MQTT::Packet.read(@socket, first_byte_in_packet)
Expand Down
8 changes: 3 additions & 5 deletions spec/mqtt_client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -845,11 +845,9 @@
expect(@read_queue.size).to eq(1)
end

it "should put PUBLISH messages on to the read queue following a wait readable exception" do
wait_readable_exception = Class.new(StandardError) do
include IO::WaitReadable
end
allow(socket).to receive(:read_nonblock).and_raise(wait_readable_exception)
it "should put PUBLISH messages on to the read queue following an IO::WaitReadable exception",
:if => OpenSSL::SSL::SSLSocket.respond_to?(:read_nonblock) do
allow(socket).to receive(:read_nonblock).and_raise(IO::WaitReadable)
socket.write("\x30\x0e\x00\x05topicpayload")
socket.rewind
client.send(:receive_packet)
Expand Down

0 comments on commit d23a669

Please sign in to comment.