Permalink
Browse files

Low-level socket timeout.

  • Loading branch information...
1 parent bbf1bec commit 080e739f7e1c65e9a9719315a77c6222c0e0353f @weppos weppos committed Mar 31, 2010
Showing with 63 additions and 5 deletions.
  1. +63 −5 lib/whois/server/adapters/base.rb
View
68 lib/whois/server/adapters/base.rb
@@ -16,13 +16,14 @@
require 'whois/answer/part'
require 'whois/answer'
+require 'net/protocol'
require 'socket'
module Whois
class Server
module Adapters
-
+
class Base
include Socket::Constants
@@ -79,18 +80,75 @@ def query_the_socket(qstring, host, port = nil)
ask_the_socket(qstring, host, port || options[:port] || DEFAULT_WHOIS_PORT)
end
+
private
def ask_the_socket(qstring, host, port)
- socket = Socket.new(AF_INET, SOCK_STREAM, IPPROTO_IP)
- sockaddr = Socket.pack_sockaddr_in(port, host)
- socket.connect(sockaddr)
+ socket = connect_to(host, port, nil)
+ socket.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1
socket.write("#{qstring}\r\n") # I could use put(foo) and forget the \n
socket.read # but write/read is more symmetric than puts/read
ensure # and I really want to use read instead of gets.
socket.close if socket # If != socket something went wrong.
end
-
+
+ def connect_to(host, port, timeout = nil)
+ sock = nil
+ if timeout
+ Timeout::timeout(timeout) do
+ sock = TCPSocket.new(host, port)
+ end
+ else
+ sock = TCPSocket.new(host, port)
+ end
+
+ io = BufferedIO.new(sock)
+ io.read_timeout = timeout
+ # Getting reports from several customers, including 37signals,
+ # that the non-blocking timeouts in 1.7.5 don't seem to be reliable.
+ # It can't hurt to set the underlying socket timeout also, if possible.
+ if timeout
+ secs = Integer(timeout)
+ usecs = Integer((timeout - secs) * 1_000_000)
+ optval = [secs, usecs].pack("l_2")
+ begin
+ io.setsockopt Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, optval
+ io.setsockopt Socket::SOL_SOCKET, Socket::SO_SNDTIMEO, optval
+ rescue Exception => ex
+ # Solaris, for one, does not like/support socket timeouts.
+ #
+ end
+ end
+ io
+ end
+
+ class BufferedIO < Net::BufferedIO # :nodoc:
+ BUFSIZE = 1024 * 16
+
+ if RUBY_VERSION < '1.9.1'
+ def rbuf_fill
+ begin
+ @rbuf << @io.read_nonblock(BUFSIZE)
+ rescue Errno::EWOULDBLOCK
+ retry unless @read_timeout
+ if IO.select([@io], nil, nil, @read_timeout)
+ retry
+ else
+ raise Timeout::Error, 'IO timeout'
+ end
+ end
+ end
+ end
+
+ def setsockopt(*args)
+ @io.setsockopt(*args)
+ end
+
+ def read
+ read_all
+ end
+ end
+
end
end

0 comments on commit 080e739

Please sign in to comment.