-
-
Save rphillips/c955dcedc657d62f11ad to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
sweet