1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
package Qooxdoo::Services::Mtr;
use strict;
use POSIX qw(setsid :sys_wait_h);
use Time::HiRes qw(usleep);
sub GetAccessibility {
return "public";
}
sub launch {
my $error = shift;
$SIG{CHLD} = \&REAPER;
defined(my $pid = fork) or do { $error->set_error(101,"Can't fork: $!");return $error};
if ($pid){
open my $x, ">/tmp/mtr_session.$pid" or do {
$error->set_error(199,"Opening /tmp/mtr_session.$$: $!");
return $error;
};
close ($x);
return $pid;
}
chdir '/' or die "Can't chdir to /: $!";
open STDOUT, ">>/tmp/mtr_session.$$"
or die "Can't write to /tmp/mtr_session.$$: $!";
open STDIN, '/dev/null' or die "Can't read /dev/null: $!";
setsid or die "Can't start a new session: $!";
open STDERR, '>&STDOUT' or die "Can't dup stdout: $!";
exec @_;
}
sub get_number {
my $error = shift;
my $data = shift;
$data = 'Undefined' unless defined $data;
if ($data =~ /^(\d+)$/){
return $1;
}
else {
$error->set_error(104,"Expected a number but got: $data");
return $error;
}
}
sub method_stop_mtr {
my $error = shift;
my $arg = shift;
my $handle = get_number($error,$arg);
return $handle if ref $handle;
my $data = "/tmp/mtr_session.".$handle;
if (-r $data){
warn "Sending kill $handle";
kill('KILL',$handle);
}
}
sub method_run_mtr
{
my $error = shift;
my $arg = shift;
my $handle = get_number($error,$arg->{handle});
my $point = get_number($error,$arg->{point});
if ($arg->{host}){
my $delay = get_number($error,$arg->{delay});
return $delay if ref $delay;
my $rounds = get_number($error,$arg->{rounds});
return $rounds if ref $rounds;
$handle = launch ($error,"mtr","-4","--raw","--report-cycles=$rounds","--interval=$delay",$arg->{host});
$point = 0;
}
return $point if ref $point;
return $handle if ref $handle;
my $data = "/tmp/mtr_session.".$handle;
if (open my $fh,$data){
my $again;
my $size;
my $rounds = 0;
do {
$size = -s $fh;
# make sure we reap any zombi instances of mtr
# this is especially important when running with speedy of fastcgi
waitpid($handle,WNOHANG);
$again = kill(0, $handle);
usleep(1000*200) if $rounds;
# print STDERR "$again, $handle, $size, $point\n";
$rounds ++;
} while ($again and $point >= $size);
if (seek $fh, $point,0){
my @array;
while (<$fh>){
if (not /^[a-z]\s/){
waitpid($handle,WNOHANG);
if (/Name or service not known/){
$error->set_error(108,"Unknown hostname.");
return $error;
}
else {
$error->set_error(107,"ERROR: $_. See $data for more information.");
return $error;
}
}
last unless /\n$/; # stop when we find an incomplete line
$point = tell($fh);
chomp;
my @line = split (/\s+/,$_);
push @array,\@line;
};
close $fh;
unlink $data unless $again;
return {
handle=>$handle,
point=>$point,
output=>\@array,
again=> $again,
}
}
else {
$error->set_error(102,"Seeking in mtr output to $point: $!");
return $error;
}
}
else {
$error->set_error(103,"Opening $data: $!");
return $error;
}
}
1;
|