Class: Netchk::ICMP
- Inherits:
-
Net::Ping
- Object
- Net::Ping
- Netchk::ICMP
- Defined in:
- lib/netchk/icmp.rb
Overview
Modified version of Net::Ping::ICMP that does not check for root privileges and uses a DGRAM socket instead of a raw socket.
Constant Summary collapse
- ICMP_ECHOREPLY =
Echo reply
0
- ICMP_ECHO =
Echo request
8
- ICMP_SUBCODE =
0
Instance Attribute Summary collapse
-
#data_size ⇒ Object
Returns the data size, i.e.
Instance Method Summary collapse
-
#bind(host, port = 0) ⇒ Object
Associates the local end of the socket connection with the given
host
andport
. -
#initialize(host = nil, port = nil, timeout = 5) ⇒ ICMP
constructor
Creates and returns a new Ping::ICMP object.
-
#ping(host = @host) ⇒ Object
Pings the
host
specified in this method or in the constructor.
Constructor Details
#initialize(host = nil, port = nil, timeout = 5) ⇒ ICMP
Creates and returns a new Ping::ICMP object. This is similar to its superclass constructor, and the port value is ignored.
30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/netchk/icmp.rb', line 30 def initialize(host = nil, port = nil, timeout = 5) @seq = 0 @bind_port = 0 @bind_host = nil @data_size = 56 @data = '' 0.upto(@data_size) { |n| @data << (n % 256).chr } @ping_id = (Thread.current.object_id ^ Process.pid) & 0xffff super(host, port, timeout) @port = nil # This value is not used in ICMP pings. end |
Instance Attribute Details
#data_size ⇒ Object
Returns the data size, i.e. number of bytes sent on the ping. The default size is 56.
26 27 28 |
# File 'lib/netchk/icmp.rb', line 26 def data_size @data_size end |
Instance Method Details
#bind(host, port = 0) ⇒ Object
Associates the local end of the socket connection with the given host
and port
. The default port is 0.
56 57 58 59 |
# File 'lib/netchk/icmp.rb', line 56 def bind(host, port = 0) @bind_host = host @bind_port = port end |
#ping(host = @host) ⇒ Object
Pings the host
specified in this method or in the constructor. If a host was not specified either here or in the constructor, an ArgumentError is raised.
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 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/netchk/icmp.rb', line 65 def ping(host = @host) super(host) bool = false socket = Socket.new( Socket::PF_INET, Socket::SOCK_DGRAM, Socket::IPPROTO_ICMP ) if @bind_host saddr = Socket.pack_sockaddr_in(@bind_port, @bind_host) socket.bind(saddr) end @seq = (@seq + 1) % 65536 pstring = 'C2 n3 A' << @data_size.to_s timeout = @timeout checksum = 0 msg = [ICMP_ECHO, ICMP_SUBCODE, checksum, @ping_id, @seq, @data].pack(pstring) checksum = checksum(msg) msg = [ICMP_ECHO, ICMP_SUBCODE, checksum, @ping_id, @seq, @data].pack(pstring) begin saddr = Socket.pack_sockaddr_in(0, host) rescue Exception socket.close unless socket.closed? return bool end start_time = Time.now socket.send(msg, 0, saddr) # Send the message begin Timeout.timeout(@timeout) { while true io_array = select([socket], nil, nil, timeout) if io_array.nil? || io_array[0].empty? raise Timeout::Error if io_array.nil? return false end ping_id = nil seq = nil data = socket.recvfrom(1500).first type = data[20, 2].unpack('C2').first case type when ICMP_ECHOREPLY if data.length >= 28 ping_id, seq = data[24, 4].unpack('n3') end else if data.length > 56 ping_id, seq = data[52, 4].unpack('n3') end end if ping_id == @ping_id && seq == @seq && type == ICMP_ECHOREPLY bool = true break end end } rescue Exception => err @exception = err ensure socket.close if socket end # There is no duration if the ping failed @duration = Time.now - start_time if bool end |