#!/usr/bin/lua local libuci_loaded, libuci = pcall(require, "uci") local function config_uci_get(option) local result if libuci_loaded then result = libuci:cursor():get("bandwidth-test","bandwidth_test",option) else result = nil end return result end local PIDfile = "/tmp/bandwidth-test-wget-pid" local singleTestDuration = tonumber(arg[1]) or tonumber(config_uci_get("single_test_duration")) or 20 local nonzeroTests = tonumber(arg[2]) or tonumber(config_uci_get("nonzero_tests")) or 5 local defaultServersList = { "http://speedtest-lon1.digitalocean.com/10mb.test", "http://www.ovh.net/files/10Mio.dat", "http://cloudharmony.com/probe/test10mb.jpg", "http://frf1-speed-02.host.twtelecom.net.prod.hosts.ooklaserver.net:8080/download?size=12000000", "http://cdn.google.cloudharmony.net/probe/test10mb.jpg", "http://deb.debian.org/debian/ls-lR.gz", "http://speedtest.catnix.cat.prod.hosts.ooklaserver.net:8080/download?size=12000000", "http://ubuntu.inode.at/ubuntu/dists/bionic/main/installer-amd64/current/images/hd-media/initrd.gz", "http://cdn.kernel.org/pub/linux/kernel/v4.x/patch-4.9.gz", "http://ftp.belnet.be/ubuntu.com/ubuntu/dists/bionic/main/installer-amd64/current/images/hd-media/initrd.gz" } local serversList if arg[3] then serversList = {} for i = 3,#arg,1 do serversList[#serversList + 1] = tostring(arg[i]) end else local temp = config_uci_get("server") serversList = type(temp) == "table" and temp or defaultServersList end if arg[1] == "-h" or arg[1] == "--help" or not serversList[1]:find("http") then local help = {"Usage: "..arg[0].." [SINGLE_TEST_DURATION] [NONZERO_TESTS] [SERVERS_LIST]", "Measures maximum available download bandwidth downloading a list of files from the internet.", "The measurement will take approximately SINGLE_TEST_DURATION*NONZERO_TESTS seconds.", "Download of each URL is attempted at most one time: multiple URLs should be provided.", "Speed in B/s is printed to STDOUT.", "", " SINGLE_TEST_DURATION fixed duration of each download process,", " if missing reads from UCI status-report (default 20)", " NONZERO_TESTS minimum number of successful downloads,", " if missing reads from UCI status-report (default 5)", " SERVERS_LIST a space-separated list of files' URLs to download,", " preferably large files.", " When running with Busybox wget, has to include http://", " and will likely fail with https://", " if missing reads from UCI status-report", " (defaults to a list of 10 MB files on various domains)"} for i = 1,#help,1 do io.stderr:write(help[i],"\n") end os.exit(1) end local function do_split(str,pat) local tbl = {} str:gsub(pat, function(x) tbl[#tbl+1]=x end) return tbl end local function do_test(server) io.stderr:write("Attempting connection to "..server.."\n") local timeout = singleTestDuration * 0.75 local pvCommand = "(wget -T"..timeout.." -q "..server.. " -O- & echo $! >&3) 3> "..PIDfile.. " | pv -n -b -t 2>&1 >/dev/null" local handlePv = io.popen(pvCommand, 'r') local handleKill = io.popen("sleep "..singleTestDuration.."; kill $(cat "..PIDfile.." 2>/dev/null) 2>/dev/null") local pvRaw = handlePv:read("*a") handleKill:close() handlePv:close() local pvArray = do_split(pvRaw,"[.%d]+") return pvArray end local function get_speed(pvArray) local t1 = tonumber(pvArray[#pvArray-3]) or 0 local d1 = tonumber(pvArray[#pvArray-2]) or 0 local t2 = tonumber(pvArray[#pvArray-1]) local d2 = tonumber(pvArray[#pvArray]) local speed = 0 if t2 and d2 then speed = (d2 - d1) / (t2 - t1) end return speed end local function remove_zeros(array) local tbl = {} for i = 1, #array do if(array[i] ~= 0) then table.insert(tbl, array[i]) end end return tbl end local function do_median(array) local temp = array local median = 0 if #temp ~= 0 then table.sort(temp) median = temp[math.floor(#array/2)+1] end return median end local function do_tests_serie() local results = {} local i = 1 while #results < nonzeroTests and serversList[i] do local test = do_test(serversList[i]) local testResult = get_speed(test) io.stderr:write(math.floor(testResult).." B/s\n") results[#results + 1] = testResult results = remove_zeros(results) i = i + 1 end local median = do_median(results) local attempted = i - 1 return median, attempted, #results end local result, attempted, successful = do_tests_serie() print(result) local message = "Maximum available bandwidth "..math.floor(result).. " B/s, attempted connection to "..attempted.. " servers, successful connection to "..successful.. " servers." io.stderr:write(message.."\n") local handle = io.popen("logger -t bandwidth-test "..message) handle:close()