Skip to content

Instantly share code, notes, and snippets.

@rphillips
Last active September 22, 2015 23:40
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rphillips/c955dcedc657d62f11ad to your computer and use it in GitHub Desktop.
Save rphillips/c955dcedc657d62f11ad to your computer and use it in GitHub Desktop.
local S = require('syscall')
local bit = require('bit')
local helpers = require('syscall.helpers')
local struct = require('struct')
local ffi = require('ffi')
local uv = require('uv')
local Object = require('core').Object
local os = require('os')
local PACKET_SIZE = 64
local ICMP_ECHO_REPLY = 0
local ICMP_ECHO = 8
local ICMP_MAX_RECV = 2048
local Stats = Object:extend()
function Stats:initialize(ip)
self.ip = ip
self.pkts_sent = 0
self.pkts_recv = 0
self.min_time = 0xffffffff
self.max_time = 0
self.tot_time = 0
self.avrg_time = 0
self.frac_loss = 0
end
local function gettime()
local clock = S.host_get_clock_service(S.mach_host_self(), "REALTIME")
return S.clock_get_time(clock).tv_nsec / 1000000.0
end
local function checksum(buffer)
local countTo, count, sum, loByte, hiByte, answer
countTo = math.floor((#buffer / 2)) * 2
count = 1
hiByte = 0
loByte = 0
sum = 0
while count < countTo do
loByte = buffer:byte(count)
hiByte = buffer:byte(count + 1)
sum = sum + (hiByte * 256 + loByte)
count = count + 2
end
-- Odd length
if countTo < #buffer then
loByte = buffer:byte(#buffer)
sum = sum + loByte
end
sum = bit.band(sum, 0xffffffff)
sum = bit.rshift(sum, 16) + bit.band(sum, 0xffff)
sum = sum + bit.rshift(sum, 16)
answer = bit.band(bit.bnot(sum), 0xffff)
answer = helpers.htons(answer)
return answer
end
function tohex(str,spacer)
return (
string.gsub(str,"(.)", function (c)
return string.format("%02X%s",string.byte(c), spacer or "")
end)
)
end
local function sendPing(stats, sock, destIP, id, seq, packet_size, callback)
local myChecksum, header, padBytes, packet, data
local sa, bytes, buf, len, poller
local function generateHeader()
return struct.pack(
'>BBHHH', ICMP_ECHO, 0, myChecksum, id, seq
)
end
-- Generate header
myChecksum = 0
header = generateHeader()
-- pad bytes
bytes = struct.size("d")
padBytes = string.rep("Q", packet_size - 8 - bytes)
data = struct.pack("d", os.clock()) .. padBytes
myChecksum = checksum(header .. data)
header = generateHeader()
packet = header .. data
buf = S.t.buffer(ICMP_MAX_RECV)
sa = S.t.sockaddr_in(1, destIP)
sock:sendto(packet, #packet, 0, sa)
poller = uv.new_poll(helpers.getfd(sock))
uv.poll_start(poller, 'r', function()
sock:recvfrom(buf, ICMP_MAX_RECV)
uv.poll_stop(poller)
uv.close(poller)
callback()
end)
return gettime()
end
local async = {}
async.forEachSeries = function(arr, iterator, callback)
local completed = 0, iterate
if #arr == 0 then
return callback()
end
iterate = function()
return iterator(arr[completed + 1], function(err)
if err then
local cb = callback
callback = function() end
return cb(err)
end
completed = completed + 1
if completed == #arr then
return callback()
end
return iterate()
end)
end
return iterate()
end
local function ping(count, host, timeout)
local runOne, stats
function runOne(stats, sequenceNumber, callback)
local sock, err, id, sent_time, onRecv
sock, err = S.socket("inet", "raw", "icmp")
if not sock then
print('count not create raw socket ' .. err)
os.exit(1)
return
end
stats.pkts_sent = stats.pkts_sent + 1
id = bit.band(S.getpid(), 0xffff)
function onRecv(err)
local delay, recv_time
recv_time = gettime()
delay = (recv_time - sent_time)
print(string.format("%d ms", delay))
stats.pkts_recv = stats.pkts_recv + 1
stats.tot_time = stats.tot_time + delay
if stats.min_time > delay then
stats.min_time = delay
end
if stats.max_time < delay then
stats.max_time = delay
end
callback()
end
sent_time = sendPing(stats, sock, host, id, sequenceNumber, PACKET_SIZE, onRecv)
end
stats = Stats:new(host)
local t = {}
for i=1, count do
table.insert(t, i - 1)
end
async.forEachSeries(t, function(i, callback)
runOne(stats, i, callback)
end, function()
print(string.format("\n---- %s LUVIT PING Statistics----", stats.ip))
if stats.pkts_sent > 0 then
stats.frac_loss = (stats.pkts_sent - stats.pkts_recv)/stats.pkts_sent
end
print(string.format("%d packets transmitted, %d packets received, %0.1f%% packet loss",
stats.pkts_sent, stats.pkts_recv, 100.0 * stats.frac_loss
))
if stats.pkts_recv > 0 then
print(string.format("round-trip (ms) min/avg/max = %d/%0.1f/%d",
stats.min_time, stats.tot_time/stats.pkts_recv, stats.max_time
))
end
print()
end)
end
ping(5, '173.194.115.33', 5000)
@rjemanuele
Copy link

sweet

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment