Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
BSD 3-Clause License

Copyright (c) 2017-2021, Mike Blumtritt. All rights reserved.
Copyright (c) 2017-2025, Mike Blumtritt. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
Expand All @@ -26,3 +26,4 @@ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

36 changes: 17 additions & 19 deletions lib/tcp-client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ def closed? = @socket.nil? || @socket.closed?
def close
@socket&.close
self
rescue *NETWORK_ERRORS
rescue *@@net_errors
self
ensure
@socket = @deadline = nil
Expand Down Expand Up @@ -338,26 +338,24 @@ def create_socket(timeout, exception)

def stem_errors(except = nil)
yield
rescue *NETWORK_ERRORS => e
rescue *@@net_errors => e
raise unless @configuration.normalize_network_errors
except && e.is_a?(except) ? raise : raise(NetworkError, e)
end

NETWORK_ERRORS =
[
Errno::EADDRNOTAVAIL,
Errno::ECONNABORTED,
Errno::ECONNREFUSED,
Errno::ECONNRESET,
Errno::EHOSTUNREACH,
Errno::EINVAL,
Errno::ENETUNREACH,
Errno::EPIPE,
IOError,
SocketError
].tap do |errors|
errors << ::OpenSSL::SSL::SSLError if defined?(::OpenSSL::SSL::SSLError)
end
.freeze
private_constant(:NETWORK_ERRORS)
@@net_errors = [
Errno::EADDRNOTAVAIL,
Errno::ECONNABORTED,
Errno::ECONNREFUSED,
Errno::EHOSTUNREACH,
Errno::ENETUNREACH,
Errno::ECONNRESET,
Errno::EINVAL,
Errno::EPIPE,
Errno::EPERM,
SocketError,
IOError
]
@@net_errors << ::OpenSSL::SSL::SSLError if defined?(::OpenSSL::SSL::SSLError)
@@net_errors.freeze
end
9 changes: 5 additions & 4 deletions lib/tcp-client/address.rb
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,11 @@ def to_s = host.index(':') ? "[#{host}]:#{port}" : "#{host}:#{port}"
# @return [Address] itself
#
def freeze
return super if frozen?
solve
@addrinfo.freeze
@host.freeze
unless frozen?
solve
@addrinfo.freeze
@host.freeze
end
super
end

Expand Down
3 changes: 1 addition & 2 deletions lib/tcp-client/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ def self.create(options = nil)
#
def initialize(options = nil)
@buffered = @keep_alive = @reverse_lookup = true
self.timeout = @ssl_params = nil
@connect_timeout_error = ConnectTimeoutError
@read_timeout_error = ReadTimeoutError
@write_timeout_error = WriteTimeoutError
Expand Down Expand Up @@ -107,7 +106,7 @@ def ssl? = @ssl_params ? true : false
def ssl_params=(value)
@ssl_params =
if value.respond_to?(:to_hash)
Hash[value.to_hash]
value.to_hash.dup
elsif value.respond_to?(:to_h)
value.nil? ? nil : value.to_h.dup
else
Expand Down
15 changes: 0 additions & 15 deletions lib/tcp-client/errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -129,19 +129,4 @@ class WriteTimeoutError < TimeoutError
#
def action = :write
end

NoOpenSSL = NoOpenSSLError # @!visibility private
NoBlockGiven = NoBlockGivenError # @!visibility private
InvalidDeadLine = InvalidDeadLineError # @!visibility private
UnknownAttribute = UnknownAttributeError # @!visibility private
NotAnException = NotAnExceptionError # @!visibility private
NotConnected = NotConnectedError # @!visibility private
deprecate_constant(
:NoOpenSSL,
:NoBlockGiven,
:InvalidDeadLine,
:UnknownAttribute,
:NotAnException,
:NotConnected
)
end
2 changes: 2 additions & 0 deletions lib/tcp-client/ssl_socket.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ def should_verify?(ssl_params)
CONTEXT_CACHE_MODE =
::OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT |
::OpenSSL::SSL::SSLContext::SESSION_CACHE_NO_INTERNAL_STORE

private_constant(:CONTEXT_CACHE_MODE)
end

private_constant(:SSLSocket)
Expand Down
13 changes: 6 additions & 7 deletions lib/tcp-client/tcp_socket.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,17 @@ class TCPSocket < ::Socket
include WithDeadline

def initialize(address, configuration, deadline)
super(address.addrinfo.ipv6? ? :INET6 : :INET, :STREAM)
addrinfo = address.addrinfo
super(addrinfo.ipv6? ? :INET6 : :INET, :STREAM)
configure(configuration)
connect_to(as_addr_in(address), deadline)
connect_to(
::Socket.pack_sockaddr_in(addrinfo.ip_port, addrinfo.ip_address),
deadline
)
end

private

def as_addr_in(address)
addrinfo = address.addrinfo
::Socket.pack_sockaddr_in(addrinfo.ip_port, addrinfo.ip_address)
end

def connect_to(addr, deadline)
return connect(addr) unless deadline.valid?
with_deadline(deadline) { connect_nonblock(addr, exception: false) }
Expand Down
2 changes: 1 addition & 1 deletion lib/tcp-client/version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@

class TCPClient
# The current version number.
VERSION = '1.0.1'
VERSION = '1.0.2'
end
8 changes: 4 additions & 4 deletions lib/tcp-client/with_deadline.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ def read_with_deadline(nbytes, deadline)
deadline.remaining_time
return fetch_avail(deadline) if nbytes.nil?
@read_buffer ||= ''.b
while @read_buffer.bytesize < nbytes
read = fetch_next(deadline)
while (diff = nbytes - @read_buffer.bytesize) > 0
read = fetch_next(deadline, diff)
read ? @read_buffer << read : (break close)
end
fetch_slice(nbytes)
Expand Down Expand Up @@ -57,8 +57,8 @@ def fetch_slice(size)
result
end

def fetch_next(deadline)
with_deadline(deadline) { read_nonblock(65_536, exception: false) }
def fetch_next(deadline, size = 65_536)
with_deadline(deadline) { read_nonblock(size, exception: false) }
end

def with_deadline(deadline)
Expand Down
6 changes: 3 additions & 3 deletions spec/lib/tcp-client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
TCPClient::Configuration.create(buffered: false, reverse_lookup: false)
end

describe 'a new instance' do
context 'with a new instance' do
subject(:client) { TCPClient.new }

it { is_expected.to be_closed }
Expand Down Expand Up @@ -34,7 +34,7 @@
end
end

describe 'a connected instance' do
context 'with a connected instance' do
before { allow_any_instance_of(Socket).to receive(:connect) }

it { is_expected.not_to be_closed }
Expand Down Expand Up @@ -75,7 +75,7 @@
end
end

describe 'an instance after #connect failed' do
context 'with an instance after #connect failed' do
subject(:client) do
TCPClient.new.tap do |instance|
instance.connect('', configuration)
Expand Down
Loading