lib/kjess/socket.rb in kjess-1.1.0 vs lib/kjess/socket.rb in kjess-1.2.0
- old
+ new
@@ -1,11 +1,11 @@
require 'socket'
module KJess
# Socket: A specialized socket that has been configure
class Socket
- class Error < KJess::Error; end
+ class Error < KJess::NetworkError; end
class Timeout < Error; end
# Internal:
# The timeout for reading in seconds. Defaults to 2
attr_accessor :read_timeout
@@ -19,11 +19,11 @@
attr_reader :write_timeout
# Internal:
# The host this socket is connected to
attr_reader :host
-
+
# Internal:
# The port this socket is connected to
attr_reader :port
# Internal
@@ -96,11 +96,11 @@
def keepalive_active?
@keepalive_active
end
# Internal: Low level socket allocation and option configuration
- #
+ #
# Using the options from the initializer, a new ::Socket is created that
# is:
#
# TCP, IPv4 only, autoclosing on exit, nagle's algorithm is disabled and has
# TCP Keepalive options set if keepalive is supported.
@@ -165,16 +165,16 @@
addrs = ::Socket.getaddrinfo(host, port, ::Socket::AF_INET, ::Socket::SOCK_STREAM )
errors = []
conn_error = lambda { raise errors.first }
sock = nil
- addrs.find( conn_error ) do |addr|
+ addrs.find( conn_error ) do |addr|
sock = connect_or_error( addr, deadline, errors )
end
return sock
end
-
+
# Internal: Connect to the destination or raise an error.
#
# Connect to the address or capture the error of the connection
#
# addr - An address returned from Socket.getaddrinfo()
@@ -206,26 +206,27 @@
sockaddr = ::Socket.pack_sockaddr_in(addr[1], addr[3])
sock = blank_socket()
sock.connect_nonblock( sockaddr )
return sock
rescue Errno::EINPROGRESS
- if IO.select(nil, [sock], nil, timeout).nil? then
+ if !wait_writable(timeout, sock)
raise Timeout, "Could not connect to #{host}:#{port} within #{timeout} seconds"
end
return connect_nonblock_finalize( sock, sockaddr )
rescue => ex
raise Error, "Could not connect to #{host}:#{port}: #{ex.class}: #{ex.message}", ex.backtrace
end
# Internal: Make sure that a non-blocking connect has truely connected.
- #
+ #
# Ensure that the given socket is actually connected to the given adddress.
#
# Returning the socket if it is and raising an Error if it isn't.
def connect_nonblock_finalize( sock, sockaddr )
sock.connect_nonblock( sockaddr )
+ return sock
rescue Errno::EISCONN
return sock
rescue => ex
raise Error, "Could not connect to #{host}:#{port}: #{ex.class}: #{ex.message}", ex.backtrace
end
@@ -258,11 +259,11 @@
#
# Returns the bytes read
def readpartial(maxlen, outbuf = nil)
return socket.read_nonblock(maxlen, outbuf)
rescue Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::ECONNRESET
- if IO.select([@socket], nil, nil, read_timeout)
+ if wait_readable(read_timeout)
retry
else
raise Timeout, "Could not read from #{host}:#{port} in #{read_timeout} seconds"
end
end
@@ -274,18 +275,26 @@
# Raises an error if it is unable to write the data to the socket within the
# write_timeout.
#
# returns nothing
def write( buf )
- until buf.length == 0
+ until buf.nil? or (buf.length == 0) do
written = socket.write_nonblock(buf)
buf = buf[written, buf.length]
end
rescue Errno::EWOULDBLOCK, Errno::EINTR, Errno::EAGAIN, Errno::ECONNRESET
- if IO.select(nil, [socket], nil, write_timeout)
+ if wait_writable(write_timeout)
retry
else
raise Timeout, "Could not write to #{host}:#{port} in #{write_timeout} seconds"
end
+ end
+
+ def wait_writable(timeout = nil, socket = @socket)
+ IO.select(nil, [socket], nil, timeout || write_timeout)
+ end
+
+ def wait_readable(timeout = nil, socket = @socket)
+ IO.select([socket], nil, nil, timeout || read_timeout)
end
end
end