From f4e1fe6c66d9ed0407a7c835f213299d193260f1 Mon Sep 17 00:00:00 2001 From: Shin Hiroe Date: Tue, 21 May 2024 09:35:09 +0900 Subject: [PATCH 1/6] Enabled to set timeout value when opening TCPSocket. --- lib/mqtt/client.rb | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/mqtt/client.rb b/lib/mqtt/client.rb index f5f3b9f..d14618c 100644 --- a/lib/mqtt/client.rb +++ b/lib/mqtt/client.rb @@ -39,6 +39,9 @@ class Client # Number of seconds to wait for acknowledgement packets (default is 5 seconds) attr_accessor :ack_timeout + # Number of seconds to connect to the server (default is 90 seconds) + attr_accessor :connect_timeout + # Username to authenticate to the server with attr_accessor :username @@ -72,6 +75,7 @@ class Client :clean_session => true, :client_id => nil, :ack_timeout => 5, + :connect_timeout => 30, :username => nil, :password => nil, :will_topic => nil, @@ -239,7 +243,17 @@ def connect(clientid = nil) unless connected? # Create network socket - tcp_socket = TCPSocket.new(@host, @port) + tcp_socket = if RUBY_VERSION.to_f >= 3.0 + TCPSocket.new(@host, @port, connect_timeout: @connect_timeout) + else + begin + Timeout.timeout(@connect_timeout) do + TCPSocket.new(@host, @port) + end + rescue Timeout::Error + raise Errno::ETIMEDOUT.new("Connection timed out for \"#{@host}\" port #{@port}") + end + end if @ssl # Set the protocol version From fa5b78daf594e46b769f1ce8dac9e6f6e4d24b0f Mon Sep 17 00:00:00 2001 From: Shin Hiroe Date: Tue, 21 May 2024 10:07:48 +0900 Subject: [PATCH 2/6] Added connect_timeout description to README. --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 3c2eafb..151ee5b 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,15 @@ client.ca_file = path_to('root-ca.pem') client.connect() ~~~ +The default timeout when opening a TCP Socket is 30 seconds. To specify it explicitly, use 'connect_timeout => 15'. + +~~~ ruby +client = MQTT::Client.connect( + :host => 'myserver.example.com', + :connect_timeout => 15 +) +~~~ + The connection can either be made without the use of a block: ~~~ ruby From 47825ffce5ee7aea3dfc65ac947e620e438336b2 Mon Sep 17 00:00:00 2001 From: Shin Hiroe Date: Tue, 21 May 2024 10:16:04 +0900 Subject: [PATCH 3/6] fix README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 151ee5b..108c6f6 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ client.ca_file = path_to('root-ca.pem') client.connect() ~~~ -The default timeout when opening a TCP Socket is 30 seconds. To specify it explicitly, use 'connect_timeout => 15'. +The default timeout when opening a TCP Socket is 30 seconds. To specify it explicitly, use 'connect_timeout =>': ~~~ ruby client = MQTT::Client.connect( From 443538984f5012f2b7e7217f4138062298cbf839 Mon Sep 17 00:00:00 2001 From: Shin Hiroe Date: Tue, 21 May 2024 10:35:03 +0900 Subject: [PATCH 4/6] refactaring for openning TCP Socket. --- lib/mqtt/client.rb | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/lib/mqtt/client.rb b/lib/mqtt/client.rb index d14618c..7de715a 100644 --- a/lib/mqtt/client.rb +++ b/lib/mqtt/client.rb @@ -243,17 +243,7 @@ def connect(clientid = nil) unless connected? # Create network socket - tcp_socket = if RUBY_VERSION.to_f >= 3.0 - TCPSocket.new(@host, @port, connect_timeout: @connect_timeout) - else - begin - Timeout.timeout(@connect_timeout) do - TCPSocket.new(@host, @port) - end - rescue Timeout::Error - raise Errno::ETIMEDOUT.new("Connection timed out for \"#{@host}\" port #{@port}") - end - end + tcp_socket = open_tcp_socket if @ssl # Set the protocol version @@ -614,6 +604,20 @@ def next_packet_id @last_packet_id end + def open_tcp_socket + if RUBY_VERSION.to_f >= 3.0 + return TCPSocket.new(@host, @port, connect_timeout: @connect_timeout) + else + begin + Timeout.timeout(@connect_timeout) do + return TCPSocket.new(@host, @port) + end + rescue Timeout::Error + raise Errno::ETIMEDOUT.new("Connection timed out for \"#{@host}\" port #{@port}") + end + end + end + # ---- Deprecated attributes and methods ---- # public @@ -636,5 +640,6 @@ def remote_port def remote_port=(args) self.port = args end + end end From 7d4422d0e0a1e4f68addbfadcf6fc94789087c55 Mon Sep 17 00:00:00 2001 From: Hiroe Shin Date: Tue, 21 May 2024 10:41:23 +0900 Subject: [PATCH 5/6] Refactaring (fix coding style). --- lib/mqtt/client.rb | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/lib/mqtt/client.rb b/lib/mqtt/client.rb index 7de715a..a01a2d4 100644 --- a/lib/mqtt/client.rb +++ b/lib/mqtt/client.rb @@ -605,17 +605,15 @@ def next_packet_id end def open_tcp_socket - if RUBY_VERSION.to_f >= 3.0 - return TCPSocket.new(@host, @port, connect_timeout: @connect_timeout) - else - begin - Timeout.timeout(@connect_timeout) do - return TCPSocket.new(@host, @port) - end - rescue Timeout::Error - raise Errno::ETIMEDOUT.new("Connection timed out for \"#{@host}\" port #{@port}") - end - end + return TCPSocket.new @host, @port, connect_timeout: @connect_timeout if RUBY_VERSION.to_f >= 3.0 + + begin + Timeout.timeout(@connect_timeout) do + return TCPSocket.new(@host, @port) + end + rescue Timeout::Error + raise Errno::ETIMEDOUT, "Connection timed out for \"#{@host}\" port #{@port}" + end end # ---- Deprecated attributes and methods ---- # @@ -640,6 +638,5 @@ def remote_port def remote_port=(args) self.port = args end - end end From a7e5da62a9ec7b7fc1dd80d567b81c0592be91d0 Mon Sep 17 00:00:00 2001 From: Hiroe Shin Date: Tue, 21 May 2024 11:01:35 +0900 Subject: [PATCH 6/6] add spec. --- lib/mqtt/client.rb | 1 + spec/mqtt_client_spec.rb | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/lib/mqtt/client.rb b/lib/mqtt/client.rb index a01a2d4..4ceeffc 100644 --- a/lib/mqtt/client.rb +++ b/lib/mqtt/client.rb @@ -612,6 +612,7 @@ def open_tcp_socket return TCPSocket.new(@host, @port) end rescue Timeout::Error + raise IO::TimeoutError, "Connection timed out for \"#{@host}\" port #{@port}" if defined? IO::TimeoutError raise Errno::ETIMEDOUT, "Connection timed out for \"#{@host}\" port #{@port}" end end diff --git a/spec/mqtt_client_spec.rb b/spec/mqtt_client_spec.rb index 28a701f..c50aaff 100644 --- a/spec/mqtt_client_spec.rb +++ b/spec/mqtt_client_spec.rb @@ -655,6 +655,19 @@ def wait_for_puback(id) client.instance_variable_set('@socket', socket) end + it "should respect connect_timeout" do + client = MQTT::Client.new(:host => '198.51.100.1', :connect_timeout => 0.1) + expect { + client.connect + }.to raise_error( + if defined? IO::TimeoutError + IO::TimeoutError + else + Errno::ETIMEDOUT + end + ) + end + it "should respect timeouts" do require "socket" rd, wr = UNIXSocket.pair