File Coverage

blib/lib/IO/Handle/Record.pm
Criterion Covered Total %
statement 130 184 70.6
branch 62 98 63.2
condition 33 53 62.2
subroutine 21 23 91.3
pod 2 5 40.0
total 248 363 68.3


line stmt bran cond sub pod time code
1             package IO::Handle::Record;
2              
3 12     12   575290 use 5.008008;
  12         44  
  12         420  
4 12     12   62 use strict;
  12         26  
  12         378  
5 12     12   54 use warnings;
  12         34  
  12         370  
6 12     12   13104 use Storable;
  12         42602  
  12         784  
7 12         106 use Class::Member::GLOB qw/record_opts
8             read_buffer expected expect_fds received_fds
9             end_of_input _received_fds
10 12     12   10686 write_buffer fds_to_send written/;
  12         112976  
11 12     12   11984 use Errno qw/EAGAIN EINTR/;
  12         15504  
  12         1374  
12 12     12   64 use Carp;
  12         34  
  12         874  
13             my $have_inet6;
14             BEGIN {
15 12     12   26 eval {
16 12         4972 require Socket6;
17 0         0 $have_inet6=1;
18             };
19             };
20 12     12   10736 use Socket;
  12         72944  
  12         8484  
21             require XSLoader;
22              
23             our $VERSION = '0.15';
24             XSLoader::load('IO::Handle::Record', $VERSION);
25              
26             use constant {
27 12         2362 HEADERLENGTH=>8, # 2 unsigned long
28 12     12   96 };
  12         100  
29              
30             # this is called from the XS stuff in recvmsg
31             sub open_fd {
32 8     8 0 18 my ($fd, $flags)=@_;
33 12     12   54 use Fcntl qw/O_APPEND O_RDONLY O_WRONLY O_RDWR O_ACCMODE/;
  12         18  
  12         628  
34 12     12   11500 use POSIX ();
  12         95652  
  12         338  
35 12     12   102 use IO::Handle ();
  12         22  
  12         26588  
36              
37 8 100       55 if( ($flags & O_ACCMODE) == O_RDONLY ) {
    100          
    50          
38 6         31 $flags='<';
39             } elsif( ($flags & O_ACCMODE) == O_WRONLY ) {
40 1 50       7 if( $flags & O_APPEND ) {
41 0         0 $flags='>>';
42             } else {
43 1         8 $flags='>';
44             }
45             } elsif( ($flags & O_ACCMODE) == O_RDWR ) {
46 1 50       4 if( $flags & O_APPEND ) {
47 0         0 $flags='+>>';
48             } else {
49 1         10 $flags='+>';
50             }
51             } else {
52 0         0 POSIX::close($fd);
53 0         0 return undef;
54             }
55              
56 8         108 my $obj=bless IO::Handle->new_from_fd($fd, $flags),
57             IO::Handle::Record::typeof($fd);
58              
59 8 100       1305 if( ref($obj)=~/Socket/ ) {
60 1         6 ${*$obj}{io_socket_domain}=socket_family($fd);
  1         7  
61 1         8 ${*$obj}{io_socket_type}=socket_type($fd);
  1         4  
62              
63 1 50 33     24 if($obj->sockdomain==AF_INET or
      33        
64             ($have_inet6 and $obj->sockdomain==&Socket6::AF_INET6) ) {
65 0 0       0 if($obj->socktype==SOCK_STREAM) {
    0          
    0          
66 0         0 ${*$obj}{io_socket_proto}=&Socket::IPPROTO_TCP;
  0         0  
67             } elsif($obj->socktype==SOCK_DGRAM) {
68 0         0 ${*$obj}{io_socket_proto}=&Socket::IPPROTO_UDP;
  0         0  
69             } elsif($obj->socktype==SOCK_RAW) {
70 0         0 ${*$obj}{io_socket_proto}=&Socket::IPPROTO_ICMP;
  0         0  
71             }
72             }
73             }
74              
75 8         160 return $obj;
76             }
77              
78             sub read_record {
79 89     89 1 11062806 my $I=shift;
80              
81             my $reader=(issock($I)
82 46 50   46   254713 ? sub { recvmsg( $_[0], $_[1], $_[2], (@_>3?$_[3]:0) ); }
83 89 50   135   2257 : sub { sysread $_[0], $_[1], $_[2], (@_>3?$_[3]:()); });
  135 100       69704  
84              
85 89 100       1342 unless( defined $I->expected ) {
86 54         1897 undef $I->end_of_input;
87 54 100       2136 undef $I->received_fds if( $I->can('received_fds') );
88 54 100       902 $I->read_buffer='' unless( defined $I->read_buffer );
89 54         4520 my $buflen=length($I->read_buffer);
90 54         1777 while( $buflen
91 68         272 my $len=$reader->( $I, $I->read_buffer, HEADERLENGTH-$buflen, $buflen );
92 68 100 100     1767 if( defined($len) && $len==0 ) { # EOF
    100 66        
    50 33        
    50          
93 5         52 undef $I->read_buffer;
94 5         174 $I->end_of_input=1;
95 5         126 return;
96             } elsif( !defined($len) && $!==EAGAIN ) {
97 14         164 return; # non blocking file handle
98             } elsif( !defined($len) && $!==EINTR ) {
99 0         0 next; # interrupted
100             } elsif( !$len ) { # ERROR
101 0         0 $len=length $I->read_buffer;
102 0         0 undef $I->read_buffer;
103 0         0 croak "IO::Handle::Record: sysread";
104             }
105 49         204 $buflen+=$len;
106             }
107 35 100 100     387 my $L=($I->record_opts && $I->record_opts->{local_encoding}) ? 'L' : 'N';
108 35 100       1460 if( $I->can('expect_fds') ) {
109 17         491 ($I->expected, $I->expect_fds)=unpack $L.'2', $I->read_buffer;
110             } else {
111 18         2518 ($I->expected)=unpack $L.'2', $I->read_buffer;
112             }
113 35         1747 $I->read_buffer='';
114             }
115              
116 70         1512 my $wanted=$I->expected;
117 70         1248 my $buflen=length($I->read_buffer);
118 70         1617 while( $buflen<$wanted ) {
119 113         614 my $len=$reader->( $I, $I->read_buffer, $wanted-$buflen, $buflen );
120              
121 113 100 66     1365 if( defined $len and $len>0 ) {
    50          
    50          
    0          
122 78         278 $buflen+=$len;
123             } elsif( defined $len ) { # EOF
124 0         0 $len=length $I->read_buffer;
125 0         0 undef $I->read_buffer;
126 0         0 croak "IO::Handle::Record: premature end of file";
127             } elsif( $!==EAGAIN ) {
128 35         747 return;
129             } elsif( $!==EINTR ) {
130 0         0 next;
131             } else {
132 0         0 undef $I->read_buffer;
133 0         0 croak "IO::Handle::Record: sysread";
134             }
135             }
136              
137 35 100 100     358 if( $I->can('expect_fds') and
      66        
138             $I->expect_fds>0 and defined $I->_received_fds ) {
139 3         152 $I->received_fds=[splice @{$I->_received_fds}, 0, $I->expect_fds];
  3         12  
140             }
141 35         536 my $rc=eval {
142 35         94 local $Storable::Eval;
143 35 100       151 $I->record_opts and $Storable::Eval=$I->record_opts->{receive_CODE};
144 35         736 Storable::thaw( $I->read_buffer );
145             };
146 35 50       12731 if( $@ ) {
147 0         0 my $e=$@;
148 0         0 $e=~s/ at .*//s;
149 0         0 croak $e;
150             }
151              
152 35         159 undef $I->expected;
153 35         662 undef $I->read_buffer;
154              
155 35         443 return @{$rc};
  35         63345  
156             }
157              
158             sub write_record {
159 37     37 1 644065 my $I=shift;
160              
161             my $writer=(issock($I)
162 28 100   28   23788 ? sub { sendmsg( $_[0], $_[1], $_[2], (@_>3?$_[3]:0) ); }
163 37 50   16   808 : sub { syswrite $_[0], $_[1], $_[2], (@_>3?$_[3]:()); });
  16 100       8650  
164              
165 37         409 my $can_fds_to_send=$I->can('fds_to_send');
166 37 100       185 if( @_ ) {
167 33 50       295 croak "IO::Handle::Record: busy"
168             if( defined $I->write_buffer );
169 33 50 66     933 my $L=($I->record_opts && $I->record_opts->{local_encoding}) ? 'L' : 'N';
170 33         946 my $msg=eval {
171 33         136 local $Storable::Deparse;
172 33         159 local $Storable::forgive_me;
173 33 100       119 $I->record_opts and do {
174 16         317 $Storable::forgive_me=$I->record_opts->{forgive_me};
175 16         219 $Storable::Deparse=$I->record_opts->{send_CODE};
176             };
177 33     1   1014 local $SIG{__WARN__}=sub {};
  1         137  
178 33 50       1099 $L eq 'L'
179             ? Storable::freeze \@_
180             : Storable::nfreeze \@_;
181             };
182 33 50       24256 if( $@ ) {
183 0         0 my $e=$@;
184 0         0 $e=~s/ at .*//s;
185 0         0 croak $e;
186             }
187              
188 33 100       100 if( $can_fds_to_send ) {
189 4         77 $I->write_buffer=pack( $L.'2', length($msg),
190             (defined $I->fds_to_send
191 17 100       122 ? 0+@{$I->fds_to_send}
192             : 0) ).$msg;
193             } else {
194 16         142 $I->write_buffer=pack( $L.'2', length($msg), 0 ).$msg;
195             }
196 33         9746 $I->written=0;
197             }
198              
199 37         457 my $written;
200              
201             # if there are file descriptors to send send them first along with the length
202             # header only. (work around a bug in the suse 11.1 kernel)
203 37 100 100     127 if( $I->written==0 and
  4   100     164  
      100        
204             $can_fds_to_send and
205             defined $I->fds_to_send and
206             @{$I->fds_to_send} ) {
207 3         45 while(!defined ($written=$writer->($I, $I->write_buffer, HEADERLENGTH))) {
208 0 0       0 if( $!==EINTR ) {
    0          
209 0         0 next;
210             } elsif( $!==EAGAIN ) {
211 0         0 return;
212             } else {
213 0         0 croak "IO::Handle::Record: syswrite";
214             }
215             }
216 3         17 $I->written+=$written;
217             }
218              
219 37   66     1031 while( $I->writtenwrite_buffer) and
      66        
220             (defined ($written=$writer->($I, $I->write_buffer,
221             length($I->write_buffer)-$I->written,
222             $I->written)) or
223             $!==EINTR) ) {
224 37 50       209 if( defined $written ) {
225 37         181 $I->written+=$written;
226             }
227             }
228 37 100       2080 if( $I->written==length($I->write_buffer) ) {
    50          
229 33         1854 undef $I->write_buffer;
230 33         740 undef $I->written;
231 33         21498 return 1;
232             } elsif( $!==EAGAIN ) {
233 4         2055 return;
234             } else {
235 0           croak "IO::Handle::Record: syswrite";
236             }
237             }
238              
239             sub read_simple_record {
240 0     0 0   my $I=shift;
241 0           local $/;
242 0           my $delim;
243 0 0         if( $I->record_opts ) {
244 0   0       $/=$I->record_opts->{record_delimiter} || "\n";
245 0   0       $delim=$I->record_opts->{field_delimiter} || "\0";
246             } else {
247 0           $/="\n";
248 0           $delim="\0";
249             }
250              
251 0           my $r=<$I>;
252 0 0         return unless( defined $r ); # EOF
253              
254 0           chomp $r;
255 0           return split /\Q$delim\E/, $r;
256             }
257              
258             sub write_simple_record {
259 0     0 0   my $I=shift;
260 0           my $rdelim;
261             my $delim;
262 0 0         if( $I->record_opts ) {
263 0   0       $rdelim=$I->record_opts->{record_delimiter} || "\n";
264 0   0       $delim=$I->record_opts->{field_delimiter} || "\0";
265             } else {
266 0           $rdelim="\n";
267 0           $delim="\0";
268             }
269              
270 0           print( $I join( $delim , @_ ), $rdelim );
271 0           $I->flush;
272             }
273              
274             *IO::Handle::write_record=\&write_record;
275             *IO::Handle::read_record=\&read_record;
276             *IO::Handle::end_of_input=\&end_of_input;
277             *IO::Handle::write_simple_record=\&write_simple_record;
278             *IO::Handle::read_simple_record=\&read_simple_record;
279             *IO::Handle::record_opts=\&record_opts;
280             *IO::Handle::expected=\&expected;
281             *IO::Socket::UNIX::expect_fds=\&expect_fds;
282             *IO::Handle::read_buffer=\&read_buffer;
283             *IO::Socket::UNIX::received_fds=\&received_fds;
284             *IO::Socket::UNIX::_received_fds=\&_received_fds;
285             *IO::Handle::written=\&written;
286             *IO::Handle::write_buffer=\&write_buffer;
287             *IO::Socket::UNIX::fds_to_send=\&fds_to_send;
288             *IO::Socket::UNIX::peercred=\&peercred;
289              
290             1;
291             __END__