Class: Ping::TCP

Inherits:
Ping
  • Object
show all
Defined in:
lib/net/ping/tcp.rb

Overview

With a TCP ping simply try to open a connection. If we are successful, assume success. In either case close the connection to be polite.

Constant Summary collapse

@@service_check =
false

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.service_checkObject Also known as: econnrefused, ecr

Returns whether or not Errno::ECONNREFUSED is considered a successful ping. The default is false.



15
16
17
# File 'lib/net/ping/tcp.rb', line 15

def self.service_check
  @@service_check
end

.service_check=(bool) ⇒ Object Also known as: econnrefused=, ecr=

Sets whether or not an Errno::ECONNREFUSED should be considered a successful ping.



22
23
24
25
26
27
# File 'lib/net/ping/tcp.rb', line 22

def self.service_check=(bool)
  unless bool.kind_of?(TrueClass) || bool.kind_of?(FalseClass)
    raise ArgumentError, 'argument must be true or false'
  end
  @@service_check = bool
end

Instance Method Details

#ping(host = @host) ⇒ Object

This method attempts to ping a host and port using a TCPSocket with the host, port and timeout values passed in the constructor. Returns true if successful, or false otherwise.

Note that, by default, an Errno::ECONNREFUSED return result will be considered a failed ping. See the documentation for the Ping::TCP.service_check= method if you wish to change this behavior.



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/net/ping/tcp.rb', line 37

def ping(host=@host)
  super(host)

  bool = false

  # Failure here most likely means bad host, so just bail.
  begin
    addr = Socket.getaddrinfo(host, port)
  rescue SocketError => err
    @exception = err
    return false
  end

  begin
    # Where addr[0][0] is likely AF_INET.
    sock = Socket.new(Socket.const_get(addr[0][0]), Socket::SOCK_STREAM, 0)

    # This may not be entirely necessary
    sock.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)

    start_time = Time.now

    begin
      # Where addr[0][3] is an IP address
      sock.connect_nonblock(Socket.pack_sockaddr_in(port, addr[0][3]))
    rescue Errno::EINPROGRESS
      # No-op, continue below
    rescue Exception => err
      # Something has gone horribly wrong
      @exception = err
      return false
    end

    resp = IO.select(nil, [sock], nil, timeout)

    if resp.nil? # Assume ECONNREFUSED if nil
      if @@service_check
        bool = true
      else
        bool = false
        @exception = Errno::ECONNREFUSED
      end
    else
      sockopt = sock.getsockopt(Socket::SOL_SOCKET, Socket::SO_ERROR)

      if sockopt.int != 0
        if @@service_check && sockopt.int == Errno::ECONNREFUSED::Errno
          bool = true
        else
          bool = false
          @exception = SystemCallError.new(sockopt.int)
        end
      else
        bool = true
      end
    end
  ensure
    sock.close if sock
  end

  # There is no duration if the ping failed
  @duration = Time.now - start_time if bool
end