Class: Ping::ICMP
- Inherits:
-
Ping
- Object
- Ping
- Ping::ICMP
- Defined in:
- lib/net/ping/icmp.rb
Overview
The Net::Ping::ICMP class encapsulates an icmp ping.
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
hostandport. -
#initialize(host = nil, port = nil, timeout = 5) ⇒ ICMP
constructor
Creates and returns a new Ping::ICMP object.
-
#ping(host = @host) ⇒ Object
Pings the
hostspecified 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, but must be created with root privileges (on UNIX systems), and the port value is ignored.
30 31 32 33 34 35 36 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 |
# File 'lib/net/ping/icmp.rb', line 30 def initialize(host=nil, port=nil, timeout=5) begin # If we have cap2, but not are root, or have net_raw, raise an error require 'cap2' current_process = Cap2.process unless Process.euid == 0 \ || current_process.permitted?(:net_raw) \ && current_process.enabled?(:net_raw) raise StandardError, 'requires root privileges or setcap net_raw' end rescue LoadError # Without cap2, raise error if we are not root unless Process.euid == 0 raise StandardError, 'requires root privileges or setcap net_raw' end end if File::ALT_SEPARATOR unless Win32::Security.elevated_security? raise 'requires elevated security' end end @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.
24 25 26 |
# File 'lib/net/ping/icmp.rb', line 24 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.
78 79 80 81 |
# File 'lib/net/ping/icmp.rb', line 78 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.
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 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
# File 'lib/net/ping/icmp.rb', line 87 def ping(host = @host) super(host) bool = false socket = Socket.new( Socket::PF_INET, Socket::SOCK_RAW, 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 |