Skip to content

Commit 64e8205

Browse files
committed
Use the open_timeout kwarg where available
1 parent e6d0d2a commit 64e8205

1 file changed

Lines changed: 32 additions & 5 deletions

File tree

lib/net/smtp.rb

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ def initialize(address, port = nil, tls: false, starttls: :auto, tls_verify: tru
263263
@tls_verify = tls_verify
264264
@tls_hostname = tls_hostname
265265
@ssl_context_params = ssl_context_params
266+
@tcpsocket_supports_open_timeout = nil
266267
end
267268

268269
# If +true+, verify th server's certificate.
@@ -659,18 +660,44 @@ def finish
659660

660661
private
661662

662-
def tcp_socket(address, port)
663-
TCPSocket.open address, port
663+
def tcp_socket(address, port, open_timeout: nil)
664+
if open_timeout
665+
TCPSocket.open(address, port, nil, nil, open_timeout: open_timeout)
666+
else
667+
TCPSocket.open(address, port)
668+
end
669+
end
670+
671+
def timeouted_connect
672+
if @tcpsocket_supports_open_timeout == nil || @tcpsocket_supports_open_timeout == true
673+
# Try to use built-in open_timeout in TCPSocket.open if:
674+
# - The current Ruby runtime is known to support it, or
675+
# - It is unknown whether the current Ruby runtime supports it (so we'll try).
676+
begin
677+
sock = tcp_socket(@address, @port, open_timeout: @open_timeout)
678+
@tcpsocket_supports_open_timeout = true
679+
return sock
680+
rescue Errno::ETIMEDOUT => e
681+
raise Net::OpenTimeout.new(e) # for compatibility with previous versions
682+
rescue ArgumentError => e
683+
raise unless e.message.include?('unknown keyword: :open_timeout') || e.message.include?('wrong number of arguments (given 5, expected 2..4)')
684+
@tcpsocket_supports_open_timeout = false
685+
end
686+
end
687+
688+
# This Ruby runtime is known not to support `TCPSocket(open_timeout:)`.
689+
# Directly fall back to Timeout.timeout to avoid performance penalty incured by rescue.
690+
Timeout.timeout(@open_timeout, Net::OpenTimeout) do
691+
tcp_socket(@address, @port)
692+
end
664693
end
665694

666695
def do_start(helo_domain, user, secret, authtype)
667696
raise IOError, 'SMTP session already started' if @started
668697
if user || secret || authtype
669698
check_auth_args authtype, user, secret
670699
end
671-
s = Timeout.timeout(@open_timeout, Net::OpenTimeout) do
672-
tcp_socket(@address, @port)
673-
end
700+
s = timeouted_connect
674701
logging "Connection opened: #{@address}:#{@port}"
675702
@socket = new_internet_message_io(tls? ? tlsconnect(s, @ssl_context_tls) : s)
676703
check_response critical { recv_response() }

0 commit comments

Comments
 (0)