Search code examples
rubysocketstcpserverreverse-lookup

Ruby TCPServer always delay on dns reverse lookup? - how to disable?


I created a TCPServer with ruby gserver.

Everytime I connect remotly to the server, it takes 2-4 seconds until connection is established.

This is only happen if I connect from remote machine.

Connection from same machine has running the service will send immidiate response.

For the connection on same machine there is no difference if I connect via localhost or via the machines ip.


I think delay depends on reverse lookup but can not localize why.

in gserver.rb it is line 263

client = @tcpServer.accept

Here the delay occurs, I do not know what is in this method.


I added all machines which are used during tests to the local hosts file. But that changed nothing.

Same happens when using Webrick, I tried to set also

BasicSocket.do_not_reverse_lookup = true

as well as direct on the resulting server socket

Socket.do_not_reverse_lookup = true

as well as on client connection socket

client.do_not_reverse_lookup = true

But that also changed nothing on delay.


Whenever connection is established, the values of remote_host and remote_ip are resolved and as defined in hosts file.


I tried that running ruby 2.2.1 on ubuntu 14.04 as well as ruby 1.9.3 running debian wheezy.

Same behavior - (long) delay on connecting service.

Q: How to fix that / disable lookup on TCPServer?


Solution

  • The problem depends on my client machine where I run on MAC OSX Mav.

    The used telnet client tries to open IPv6 connection and afterwards IPv4.

    To solve the delay, just open connection with

    telnet -4 my-server 3333
    

    I have build a small connect echo servive where you can check resolves and timings.

    If you change NO_REVERSE_LOOKUP you will get IPs or ADDRESSes and if not resolveable, different response times.

    require 'socket'
    
    NO_REVERSE_LOOKUP = true
    CONNECT_PORT = 3333
    
    puts "#{Time.now} Starting service on port: #{CONNECT_PORT}"
    
    # the full hell - just to test if anything meets what we want
    TCPServer.do_not_reverse_lookup = NO_REVERSE_LOOKUP
    BasicSocket.do_not_reverse_lookup = NO_REVERSE_LOOKUP
    Socket.do_not_reverse_lookup = NO_REVERSE_LOOKUP
    
    srv = TCPServer.open(CONNECT_PORT)
    
    puts "#{Time.now} Waiting for client"
    
    client = srv.accept
    
    puts "#{Time.now} Client connected"
    
    client.do_not_reverse_lookup = NO_REVERSE_LOOKUP
    
    client.print "Hello connected\n"
    
    # in case that we disabled reverse lookup, we should only receive IP Adresses
    
    puts "#{Time.now} Getting server address infos" 
    
    puts "SERVER INFO:"
    puts NO_REVERSE_LOOKUP ? client.addr(:numeric) : client.addr(:hostname)
    
    puts ""
    
    puts "#{Time.now} Getting remote client infos"
    
    puts "REMOTE INFO:"
    puts NO_REVERSE_LOOKUP ? client.peeraddr(:numeric) : client.peeraddr(:hostname)
    
    ###
    
    puts "#{Time.now} Closing connection"
    
    client.close
    
    puts "#{Time.now} End"
    

    Thanks to drbrain from #ruby-lang irc for pointing me to the IPv6 problem.