File Coverage

blib/lib/Linux/Proc/Net/TCP/Base.pm
Criterion Covered Total %
statement 33 65 50.7
branch 6 28 21.4
condition 1 8 12.5
subroutine 4 22 18.1
pod n/a
total 44 123 35.7


line stmt bran cond sub pod time code
1             package Linux::Proc::Net::TCP::Base;
2              
3 1     1   7 use strict;
  1         2  
  1         41  
4 1     1   5 use warnings;
  1         3  
  1         27  
5              
6 1     1   5 use Carp;
  1         1  
  1         1867  
7              
8             my %regexp = ( tcp => qr/^\s*
9             (\d+):\s # sl - 0
10             ([\dA-F]{8}(?:[\dA-F]{24})?):([\dA-F]{4})\s # local address and port - 1 & 2
11             ([\dA-F]{8}(?:[\dA-F]{24})?):([\dA-F]{4})\s # remote address and port - 3 & 4
12             ([\dA-F]{2})\s # st - 5
13             ([\dA-F]{8}):([\dA-F]{8})\s # tx_queue and rx_queue - 6 & 7
14             (\d\d):([\dA-F]{8}|F{9,}|1AD7F[\dA-F]{6})\s # tr and tm->when - 8 & 9
15             ([\dA-F]{8})\s+ # retrnsmt - 10
16             (\d+)\s+ # uid - 11
17             (\d+)\s+ # timeout - 12
18             (\d+)\s+ # inode - 13
19             (\d+)\s+ # ref count - 14
20             ((?:[\dA-F]{8}){1,2}) # memory address - 15
21             (?:
22             \s+
23             (\d+)\s+ # retransmit timeout - 16
24             (\d+)\s+ # predicted tick - 17
25             (\d+)\s+ # ack.quick - 18
26             (\d+)\s+ # sending congestion window - 19
27             (-?\d+) # slow start size threshold - 20
28             )?
29             \s*
30             (.*) # more - 21
31             $
32             /xi,
33              
34             udp => qr/^\s*
35             (\d+):\s # sl - 0
36             ([\dA-F]{8}(?:[\dA-F]{24})?):([\dA-F]{4})\s # local address and port - 1 & 2
37             ([\dA-F]{8}(?:[\dA-F]{24})?):([\dA-F]{4})\s # remote address and port - 3 & 4
38             ([\dA-F]{2})\s # st - 5
39             ([\dA-F]{8}):([\dA-F]{8})\s # tx_queue and rx_queue - 6 & 7
40             (\d\d):([\dA-F]{8}|F{9,}|1AD7F[\dA-F]{6})\s # tr and tm->when - 8 & 9
41             ([\dA-F]{8})\s+ # retrnsmt - 10
42             (\d+)\s+ # uid - 11
43             (\d+)\s+ # timeout - 12
44             (\d+)\s+ # inode - 13
45             (\d+)\s+ # ref count - 14
46             ((?:[\dA-F]{8}){1,2}) # memory address - 15
47             (?:
48             \s+
49             (\d+) # drops - 16
50             )?
51             \s*
52             (.*) # more - 17
53             $
54             /xi
55             );
56              
57             sub _read {
58 1     1   3 my $class = shift;
59 1 50       4 @_ & 1 and croak "Usage: $class->read(\%opts)";
60 1         10 my %opts = @_;
61              
62 1   50     7 my $proto = delete $opts{_proto} || 'tcp';
63              
64 1         4 my $ip4 = delete $opts{ip4};
65 1         1 my $ip6 = delete $opts{ip6};
66 1         2 my $mnt = delete $opts{mnt};
67 1         2 my $files = delete $opts{files};
68              
69 1 50       4 %opts and croak "Unknown option(s) ". join(", ", sort keys %opts);
70              
71 1         2 my @fn;
72 1 50       4 if ($files) {
73 1         4 @fn = @$files;
74             }
75             else {
76 0 0       0 $mnt = "/proc" unless defined $mnt;
77              
78 0 0 0     0 unless (-d $mnt and (stat _)[12] == 0) {
79 0         0 croak "$mnt is not a proc filesystem";
80             }
81              
82 0 0 0     0 push @fn, "$mnt/net/${proto}" unless (defined $ip4 and not $ip4);
83 0 0       0 push @fn, "$mnt/net/${proto}6" if (defined $ip6 ? $ip6 : -f "$mnt/net/${proto}6");
    0          
84             }
85              
86 1 50       5 my $regexp = $regexp{$proto} or croak "Internal error: unexpected protocol '$proto'";
87              
88 1         2 my @entries;
89 1         3 for my $fn (@fn) {
90 1         6 local $_;
91 1 50       92 open my $fh, '<', $fn
92             or croak "Unable to open $fn: $!";
93 1         649 <$fh>; # discard header
94 1         11 while (<$fh>) {
95 10 50       170 if (my @entry = $_ =~ $regexp) {
96 10         14 my $entry = \@entry;
97 10         25 bless $entry, "${class}::Entry";
98 10         57 push @entries, $entry
99             }
100             else {
101 0         0 warn "unparseable line: $_";
102             }
103             }
104             }
105 1         7 bless \@entries, $class;
106             }
107              
108             package Linux::Proc::Net::TCP::Base::Entry;
109              
110             sub _hex2ip {
111 0     0     my $bin = pack "C*" => map hex, $_[0] =~ /../g;
112 0           my @l = unpack "L*", $bin;
113 0 0         if (@l == 4) {
    0          
114 0           return join ':', map { sprintf "%x:%x", $_ >> 16, $_ & 0xffff } @l;
  0            
115             }
116             elsif (@l == 1) {
117 0           return join '.', map { $_ >> 24, ($_ >> 16 ) & 0xff, ($_ >> 8) & 0xff, $_ & 0xff } @l;
  0            
118             }
119 0           else { die "internal error: bad hexadecimal encoded IP address '$_[0]'" }
120             }
121              
122 0     0     sub sl { shift->[ 0] }
123 0     0     sub local_address { _hex2ip shift->[ 1] }
124 0     0     sub local_port { hex shift->[ 2] }
125 0     0     sub rem_address { _hex2ip shift->[ 3] }
126 0     0     sub rem_port { hex shift->[ 4] }
127             # st is defined in subclasses
128 0     0     sub tx_queue { hex shift->[ 6] }
129 0     0     sub rx_queue { hex shift->[ 7] }
130 0     0     sub timer { shift->[ 8] }
131 0     0     sub retrnsmt { hex shift->[10] }
132 0     0     sub uid { shift->[11] }
133 0     0     sub timeout { shift->[12] }
134 0     0     sub inode { shift->[13] }
135 0     0     sub reference_count { shift->[14] }
136 0     0     sub memory_address { hex shift->[15] }
137              
138 0     0     sub ip4 { length(shift->[ 1]) == 8 }
139 0     0     sub ip6 { length(shift->[ 1]) == 32 }
140              
141             sub tm_when { # work around bug in Linux kernel
142 0     0     my $when = shift->[9];
143 0 0         $when =~ /^(?:F{8,}|1AD7F[\dA-F]{6})$/ ? -1 : hex $when
144             }
145              
146              
147              
148             1;