From: Wejn Date: 2003-01-29T08:37:32+09:00 Subject: Re: ping with ruby > For telnet and ftp I have found how to do, but no for ping. The following source comes from RAA and it's modified by me (to suit my own needs) ... enjoy :) #---= begin =--------------------------------------------------------------- #!/usr/bin/env ruby =begin Copyright(c) 2001 arton, under GPL2. Modifications and fixes 2003 Wejn == SYNOPSIS require 'icmpping' result = ICMPPing.ping hostname [, timeout(millisecs) [, packetsize(<1024)]] == Return Value -1 : Any Socket Error -2 : Timeout -3 : Not root >=0: round trip time (in milliseconds) == Notes Only Linux now supported You must be root Miliseconds now work correctly Only a class now =end require 'socket' require 'timeout' class ICMPPing IPPROTO_ICMP = 1 ICMP_ECHO = 8 ICMP_ECHOREPLY = 0 DEF_PACKET_SIZE = 64 MAX_PACKET_SIZE = 1024 def ICMPPing.ping(host, timeout = 1000, dlen = self::DEF_PACKET_SIZE) begin raise ArgumentError, "Packet too long" if dlen > MAX_PACKET_SIZE hp = [Socket::AF_INET, 0, Socket.gethostbyname(host)[3], 0, 0] s = Socket.new(Socket::AF_INET, Socket::SOCK_RAW, IPPROTO_ICMP) rescue Errno::EPERM $stderr.puts "Error: #{$!.message}" if $VERBOSE return -3 rescue $stderr.puts "Error: #{$!.message}" if $VERBOSE return -1 end start = Time.now.to_f * 1000 id = $$ & 0xffff icmph = [ ICMP_ECHO, 0, 0, id, 0, start.to_i & 0xffffffff, nil ] icmph[6] = "E" * dlen dat = icmph.pack("C2n3Na*") cksum = checksum(((dat.length & 1) ? (dat + "\0") : dat).unpack("n*")) dat[2], dat[3] = cksum >> 8, cksum & 0xff begin s.send dat, 0, hp.pack("v2a*N2") timeout(timeout / 1000.0) do while true rdat = s.recvfrom(self::MAX_PACKET_SIZE + 500) icmpdat = rdat[0].slice((rdat[0][0] & 0x0f) * 4..-1) resp = icmpdat.unpack("C2n3N") next if resp[0] != ICMP_ECHOREPLY || resp[3] != id break end end rescue TimeoutError $stderr.puts "Error: #{$!.message}" if $VERBOSE return -2 rescue $stderr.puts "Error: #{$!.message}" if $VERBOSE return -1 end Time.now.to_f * 1000 - start end def ICMPPing.checksum(n) ck = 0 n.each{ |v| ck += v } ck = (ck >> 16) + (ck & 0xffff) ck += ck >> 16 ~ck end end if $0 == __FILE__ if ARGV.empty? print "usage: icmpping.rb [timeout(ms=2000)]\n" exit 1 end $VERBOSE = true rd = ICMPPing.ping(ARGV[0], (ARGV[1] || "2000").to_i) if rd < 0 exit rd.abs else puts "#{ICMPPing::DEF_PACKET_SIZE} bytes, rtt: #{rd} msec" end end #---= end =--------------------------------------------------------------- W. -- Wejn (svamberk.net's Linux section, fi.muni.cz student, linuxfan) >>> Bored? Want hours of entertainment? <<< >>> Just set the initdefault to 6! <<<