File Coverage

lib/RPC/Switch/Client/Tiny/Netstring.pm
Criterion Covered Total %
statement 42 55 76.3
branch 13 32 40.6
condition 2 3 66.6
subroutine 7 8 87.5
pod 0 4 0.0
total 64 102 62.7


line stmt bran cond sub pod time code
1             # Netstring messages for RPC::Switch::Client::Tiny
2             #
3             package RPC::Switch::Client::Tiny::Netstring;
4              
5 21     21   72792 use strict;
  21         51  
  21         590  
6 21     21   106 use warnings;
  21         43  
  21         526  
7 21     21   124 use Exporter 'import';
  21         61  
  21         11444  
8             our @EXPORT = qw(netstring_read netstring_write);
9              
10             our $VERSION = 1.14;
11              
12             # Returns data in $buf and number of bytes read, or undef on EOF
13             # (see: https://www.perlmonks.org/?node_id=1173814)
14             #
15             sub sysreadfull {
16 4812     4812 0 9612 my ($file, $len) = ($_[0], $_[2]); # need ref on $buf here
17 4812         8461 my $n = 0;
18 4812         10603 while ($len - $n) {
19 4812         39447 my $i = sysread($file, $_[1], $len - $n, $n);
20 4812 50       13189 if (defined $i) {
    0          
21 4812 50       9261 if ($i == 0) {
22 0         0 return $n;
23             } else {
24 4812         13073 $n += $i;
25             }
26 1     1   404 } elsif ($!{EINTR}) {
  1         1295  
  1         8  
27 0         0 redo;
28             } else {
29 0 0       0 return $n ? $n : undef;
30             }
31             }
32 4812         14912 return $n;
33             }
34              
35             # Returns number of bytes written. Catches partial writes and
36             # interrupts but returns on file-errors like the print call.
37             #
38             sub syswritefull {
39 0     0 0 0 my ($file, $buf) = @_;
40 0         0 my $len = length($buf);
41 0         0 my $n = 0;
42 0         0 while ($len - $n) {
43 0         0 my $i = syswrite($file, $buf, $len - $n, $n);
44 0 0       0 if (defined($i)) {
    0          
45 0         0 $n += $i;
46             } elsif ($!{EINTR}) {
47 0         0 redo;
48             } else {
49 0 0       0 return $n ? $n : undef;
50             }
51             }
52 0         0 return $n;
53             }
54              
55             # netstring proto: http://cr.yp.to/proto/netstrings.txt
56             #
57             sub netstring_write {
58 1099     1099 0 37173 my ($s, $str) = @_;
59              
60             # A print call catches partial writes and interrupts,
61             # but it will return on file-errors like 'Broken Pipe'.
62             #
63             # TODO: $client->stop() does not interrupt a blocking print
64             #
65 1099         220905 my $res = print $s '' . length($str) . ':' . $str . ',';
66 1099         14638 $s->flush();
67 1099         16987 return $res;
68             }
69              
70             # returns received netstring, or empty string on EOF
71             # dies on error -> use eval {..}
72             #
73             sub netstring_read {
74 1174     1174 0 27566 my ($s) = @_;
75 1174         4611 my ($c, $b, $n) = ('', '', '');
76              
77             # Break on EINTR only before start of message,
78             # so that a partial message is never discarded.
79             #
80 1174         181309 my $res = sysread($s,$c,1);
81 1174         5320 while ($res) {
82 3753 100       8388 if ($c ne ':') {
83 2694 50       15116 die "bad netstring: $c" unless ($c =~ /\d+/);
84 2694         5328 $n .= $c;
85             } else {
86 1059 50       2415 die "bad netstring: $c" if ($n eq '');
87 1059         2226 last;
88             }
89 2694         5746 $res = sysreadfull($s,$c,1);
90             }
91 1174 100 66     5823 if ($res && ($res = sysreadfull($s,$b,$n))) {
92 1059 50       3347 die "bad netstring: $b" if ($res != $n);
93 1059 50       3332 if ($res = sysreadfull($s,$c,1)) {
94 1059 50       2837 die "bad netstring: $c" unless ($c eq ',');
95 1059         5625 return $b;
96             }
97             }
98 115 50       2433 die "EINTR" if $!{EINTR};
99 115 50       2794 die "netstring read error: $!" unless defined $res;
100 115         1083 return ''; # EOF
101             }
102              
103             1;
104              
105             __END__