App-SpeedTest

 view release on metacpan or  search on metacpan

speedtest  view on Meta::CPAN

#!/pro/bin/perl

# speedtest - test network speed using speedtest.net
# (m)'26 [2026-01-09] Copyright H.M.Brand 2014-2026

require 5.010;
use strict;
use warnings;

our $VERSION = "0.31";
our $CMD = $0; $CMD =~ s{.*/}{};

sub usage {
    my $err = shift and select STDERR;
    (my $p = $0) =~ s{.*/}{};
    print <<"EOH";
usage: $p [ --no-geo | --country=NL ] [ --list | --ping[=n] ] [ options ]
       --geo          use Geo location (default true) for closest testserver
       --all          include *all* servers (default only in own country)
    -c --country=IS   use ISO country code for closest test server
       --list-cc      list country codes and countries with server count
    -1 --one-line     show summary in one line
    -C --csv          output in CSV (stamp,id,ping,tests,direction,speed,min,max)
       --csv-eol-unix EOL = NL (default = CR NL) implies -C
    -P --prtg         output in XML for PRTG

    -l --list         list test servers in chosen country sorted by distance
    -p --ping[=40]    list test servers in chosen country sorted by latency
       --url          show server url in list

    -s --server=nnn   use testserver with id nnn
       --server=file  use testserver from file
    -t --timeout=nnn  set server timeout to nnn seconds
       --url=sss      use specific server url (do not scan) ext php
       --mini=sss     use specific server url (do not scan) ext from sss
       --download     test download speed (default true)
       --upload       test upload   speed (default true)
    -q --quick[=20]   do a      quick test (only the fastest 20 tests)
    -Q --realquick    do a real quick test (only the fastest 10 tests)
    -T --try[=5]      try all tests on the n fastest servers
    -U --skip-undef   skip results with no actual measurements

    -v --verbose[=1]  set verbosity
       --simple       alias for -v0
       --ip           show IP for server
    -V --version      show version and exit
    -? --help         show this help
       --man          show the builtin manual (requires nroff)
       --info         show the builtin manual as plain text

  $p --list
  $p --ping --country=BE
  $p
  $p -s 4358
  $p --url=http://ookla.extraip.net
  $p -q --no-download
  $p -Q --no-upload

EOH
    exit $err;
    } # usage

use Getopt::Long qw(:config bundling noignorecase);
my $opt_c = "";
my $opt_v = 1;
my $opt_d = 1;
my $opt_u = 1;
my $opt_g = 1;
my $opt_q = 0;
my $opt_T = 1;
my $unit  = [ 1, "bit" ];
GetOptions (
    "help|h|?"		=> sub { usage (0); },
    "V|version!"	=> sub { print "$CMD [$VERSION]\n"; exit 0; },
    "v|verbose:2"	=>    \$opt_v,
      "simple!"		=> sub { $opt_v = 0; },
      "man"		=> sub { pod_nroff (); },
      "info"		=> sub { pod_text  (); },

      "all!"		=> \my $opt_a,
    "g|geo!"		=>    \$opt_g,
    "c|cc|country=s"	=>    \$opt_c,
      "list-cc!"	=> \my $opt_cc,
    "1|one-line!"	=> \my $opt_1,
    "C|csv!"		=> \my $opt_C,
      "csv-eol-unix|".
      "csv-eol-nl!"	=> \my $opt_CNL,
    "P|prtg!"		=> \my $opt_P,

    "l|list!"		=> \my $list,
    "p|ping:40"		=> \my $opt_ping,
      "url:s"		=> \my $url,
      "ip!"		=> \my $ip,

    "B|bytes"		=> sub { $unit = [ 8, "byte" ] },

    "T|try:5"		=>    \$opt_T,
    "s|server=s"	=> \my @server,
    "t|timeout=i"	=> \my $timeout,
    "d|download!"	=>    \$opt_d,
    "u|upload!"		=>    \$opt_u,
    "q|quick|fast:20"	=>    \$opt_q,
    "Q|realquick:10"	=>    \$opt_q,
    "U|skip-undef!"	=> \my $opt_U,

    "m|mini=s"		=> \my $mini,
      "source=s"	=> \my $source,	# NYI
    ) or usage (1);

$opt_CNL and $opt_C++;
$opt_C || $opt_P and $opt_v = 0;

use LWP::UserAgent;
use XML::Simple; # Can safely be replaced with XML::LibXML::Simple
use HTML::TreeBuilder;
use Term::ANSIColor;
use Time::HiRes qw( gettimeofday tv_interval );
use List::Util  qw( first sum );
use Socket      qw( inet_ntoa );
use Math::Trig;

sub pod_text {
    require Pod::Text::Color;
    my $m = $ENV{NO_COLOR} ? "Pod::Text" : "Pod::Text::Color";
    my $p = $m->new ();
    open my $fh, ">", \my $out;
    $p->parse_from_file ($0, $fh);
    close $fh;
    print $out;
    exit 0;
    } # pod_text

sub pod_nroff {
    first { -x "$_/nroff" } grep { -d } split m/:+/ => $ENV{PATH} or pod_text ();

    require Pod::Man;
    my $p = Pod::Man->new ();
    open my $fh, "|-", "nroff", "-man";
    $p->parse_from_file ($0, $fh);
    close $fh;
    exit 0;
    } # pod_nroff

# Debugging. Prefer Data::Peek over Data::Dumper if available
{   use Data::Dumper;
    my $dp = eval { require Data::Peek; 1; };
    sub ddumper {



( run in 0.545 second using v1.01-cache-2.11-cpan-5a3173703d6 )