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   76230 use strict;
  21         52  
  21         590  
6 21     21   105 use warnings;
  21         42  
  21         528  
7 21     21   104 use Exporter 'import';
  21         41  
  21         11494  
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 4816     4816 0 10094 my ($file, $len) = ($_[0], $_[2]); # need ref on $buf here
17 4816         8159 my $n = 0;
18 4816         14746 while ($len - $n) {
19 4816         40298 my $i = sysread($file, $_[1], $len - $n, $n);
20 4816 50       13955 if (defined $i) {
    0          
21 4816 50       9051 if ($i == 0) {
22 0         0 return $n;
23             } else {
24 4816         11649 $n += $i;
25             }
26 1     1   414 } elsif ($!{EINTR}) {
  1         1367  
  1         8  
27 0         0 redo;
28             } else {
29 0 0       0 return $n ? $n : undef;
30             }
31             }
32 4816         14933 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 1100     1100 0 34533 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 1100         64194 my $res = print $s '' . length($str) . ':' . $str . ',';
66 1100         12845 $s->flush();
67 1100         18798 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 1175     1175 0 26286 my ($s) = @_;
75 1175         5068 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 1175         182550 my $res = sysread($s,$c,1);
81 1175         7729 while ($res) {
82 3756 100       8533 if ($c ne ':') {
83 2696 50       15797 die "bad netstring: $c" unless ($c =~ /\d+/);
84 2696         5922 $n .= $c;
85             } else {
86 1060 50       2618 die "bad netstring: $c" if ($n eq '');
87 1060         2190 last;
88             }
89 2696         7213 $res = sysreadfull($s,$c,1);
90             }
91 1175 100 66     6001 if ($res && ($res = sysreadfull($s,$b,$n))) {
92 1060 50       4673 die "bad netstring: $b" if ($res != $n);
93 1060 50       2158 if ($res = sysreadfull($s,$c,1)) {
94 1060 50       3361 die "bad netstring: $c" unless ($c eq ',');
95 1060         6399 return $b;
96             }
97             }
98 115 50       2758 die "EINTR" if $!{EINTR};
99 115 50       2804 die "netstring read error: $!" unless defined $res;
100 115         1094 return ''; # EOF
101             }
102              
103             1;
104              
105             __END__