RubyPing – custom ping and it’s future

I ride the train almost everyday for an hour each way and work using my laptop. It was my hope that the wi-fi on the train worked sufficiently that I’d have a constant Internet connection but this is not the case. The wi-fi drops out often and make working miserable.

To correct this I purchased a mobile hotspot from T-Mobile, the MF-61, and it works a bit better. There are less drop outs so I can work more. There is a dilemma however. When I browse the web and there’s not connection I can sit an stare at a spinning cursor for sometime before I realize what’s happened. To give me more information I open a command window (Win7) and run PING endlessly. This window is placed far to one size of the screen and my work covers almost all of it so that I an peek at the scrolling endless line of data to quickly access my connection.

The dilemma is that PING in Windows and in Cygwin engages every second or so which is not what I want. I pay for my connection through the hotspot so every packet counts more or less. It’s not a lot of data but it is the principle that counts to me. I just want to know every so often what the connection status is, am I connect or not. Hence, I wrote RubyPing in, well, ruby.

 

# Customized PING
#
# TODO
# 1 - add logging. I'd like to record my train rides for later analysis. What
# might be really good is if I could get the geolocation at the same time from my
# phone and add it to the log. Hmmmm.
#
# If the laptop and the phone where sharing a network connection, in mu case
# my mobile hotspot, the laptop could query the phone for it's geo location.
# This would likely require a little app running on the phone serving this information
# when it got a request. Is a tiny webserver available for the Android?
#
# What's the absolute easiest way to do this?
# One way is a GPS Logging app on the phone. Log the timestamped data
# and send/grab that file. Merge that file with the one RubyPing produces
# creating data that can be mapped.
#
# https://github.com/defunkt/choice
require 'net/ping'
require 'resolv'
require 'choice'
def InMs(rawNumber)
 return (rawNumber * 1000).truncate()
end
Choice.options do
 option :host do
 short '-h'
 long '--host=HOST'
 desc 'The hostname or ip of the host to bind to (default 127.0.0.1)'
 default '127.0.0.1'
 end
option :delay do
 short '-d'
 long '--delay=delayInSec'
 desc 'The seconds to delay until the next PING (default 5)'
 default 5
 end
option :repeatCount do
 short '-r'
 long '--repeatCount=Number'
 desc 'The number of times to repeat (default 5)'
 default 5
 end
option :help do
 long '--help'
 desc 'Show this message'
 end
end
@executeDir = File.expand_path File.dirname(__FILE__)
@logFilePath = File.join(@executeDir, "pinglog.txt")
@ip = Resolv.getaddress Choice[:host]
@delay = Choice[:delay]
@icmp = Net::Ping::ICMP.new(host=@ip)
rtary = []
pingfails = 0
repeat = Choice[:repeatCount].to_i
puts 'starting to ping ' + Choice[:host] + ' at ' + @ip
(1..repeat).each do
 t = DateTime.now
 timestamp = t.strftime("%m/%d/%Y %H:%M:%S") # 07/24/2006 09:09:03
 @msg = '';
 begin
   if @icmp.ping
     rtary << @icmp.duration
     #puts "host replied in #{@icmp.duration}"
     @msg = '%4.0d ms host replied at %s' % [InMs(@icmp.duration), timestamp]
   else
     pingfails += 1
     @msg =" !!! timeout at %s" % timestamp
   end
   puts @msg
   File.open(@logFilePath, 'a') { |file| file.write(@msg + "\n") }
   rescue Exception => e
   puts e.message
   puts.e.backtrace.inspect
 end
 sleep @delay.to_i
end
avg = rtary.inject(0) {|sum, i| sum + i}/(repeat - pingfails)
#puts "Average round-trip is #{avg}\n"
puts 'Average round-trip is %d ms' % InMs(avg)
puts "#{pingfails} packets were dropped"

The screen output looks like this:

41 ms host replied at 12/19/2013 07:05:25
41 ms host replied at 12/19/2013 07:05:30
51 ms host replied at 12/19/2013 07:05:35
!!! timeout at 12/19/2013 07:05:40
24 ms host replied at 12/19/2013 07:05:50
32 ms host replied at 12/19/2013 07:05:55
51 ms host replied at 12/19/2013 07:06:00

Both resolved pings and timeouts are handled in the code as evident from above.

The log file format looks like this:

41 ms host replied at 12/19/2013 07:05:25
41 ms host replied at 12/19/2013 07:05:30
51 ms host replied at 12/19/2013 07:05:35
!!! timeout at 12/19/2013 07:05:40
24 ms host replied at 12/19/2013 07:05:50
32 ms host replied at 12/19/2013 07:05:55
51 ms host replied at 12/19/2013 07:06:00

Exactly the same (no surprise).

Launching if from the command line it accepts three parameters, the host to ping by name or ip, the delay between pings and the number of repetitions.

Typical launch:

ruby rubyping.rb -h google.com -d 5 -r 999

Ping google.com every 5 seconds for 999 times.  Given the latency of the ping, the actual delay is more like 12 second BUT in principle it works as desired.

AND, the way it’s written, it logs the pings to a log file. I did this for a follow on project I have in mind. To gather location data as I am traveling, merge that data with the ping log and come up with active/dead spots along my trip.

A few days ago I found an app for my Android phone called GPS Logger that logs the location of the phone via GPS to a file in a variety of formats. This data along with my ping log can now create the data I am after.

This led me to find open-source server software, OpenGTS project, that consumes GPS logs and report on it including visual mapping a la GIS. There’s an enterprise version of the software too if need be.

The next step is to merge the ping log with the GPS log and come up with a data source that can be used by other apps like OpenGTS.

 


Leave a Reply

Your email address will not be published. Required fields are marked *