File Coverage

blib/lib/IO/Framed.pm
Criterion Covered Total %
statement 12 12 100.0
branch n/a
condition 2 3 66.6
subroutine 4 4 100.0
pod 0 1 0.0
total 18 20 90.0


line stmt bran cond sub pod time code
1             package IO::Framed;
2              
3 3     3   76410 use strict;
  3         7  
  3         85  
4 3     3   14 use warnings;
  3         9  
  3         258  
5              
6             our $VERSION = '0.04-TRIAL1';
7              
8             =encoding utf-8
9              
10             =head1 NAME
11              
12             IO::Framed - Convenience wrapper for frame-based I/O
13              
14             =head1 SYNOPSIS
15              
16             Reading:
17              
18             #See below about seed bytes.
19             my $iof = IO::Framed->new( $fh, 'seed bytes' );
20              
21             #This returns undef if the $in_fh doesn’t have at least
22             #the given length (5 in this case) of bytes to read.
23             $frame = $iof->read(5);
24              
25             Writing, unqueued (i.e., for blocking writes):
26              
27             #The second parameter (if given) is executed immediately after the final
28             #byte of the payload is written. For blocking I/O this happens
29             #before the following method returns.
30             $iof->write('hoohoo', sub { print 'sent!' } );
31              
32             Writing, queued (for non-blocking writes):
33              
34             $iof->enable_write_queue();
35              
36             #This just adds to a memory queue:
37             $iof->write('hoohoo', sub { print 'sent!' } );
38              
39             #This will be 1, since we have 1 message/frame queued to send.
40             $iof->get_write_queue_count();
41              
42             #Returns 1 if it empties out the queue; 0 otherwise.
43             #Partial frame writes are accommodated; the callback given as 2nd
44             #argument to write() only fires when the queue item is sent completely.
45             my $empty = $iof->flush_write_queue();
46              
47             You can also use C and C, which
48             contain just the read and write features. (C is actually a
49             subclass of them both.)
50              
51             =head1 DESCRIPTION
52              
53             While writing L I noticed that I was reimplementing some of the
54             same patterns I’d used in L to parse frames from a stream:
55              
56             =over
57              
58             =item * Only read() entire frames, with a read queue for any partials.
59              
60             =item * Continuance when a partial frame is delivered.
61              
62             =item * Write queue with callbacks for non-blocking I/O
63              
64             =item * Signal resilience: resume read/write after Perl receives a trapped
65             signal rather than throwing/giving EINTR. (cf. L)
66              
67             =back
68              
69             These are now made available in this distribution.
70              
71             =head1 ABOUT READS
72              
73             The premise here is that you expect a given number of bytes at a given time
74             and that a partial read should be continued once it is sensible to do so.
75              
76             As a result, C will throw an exception if the number of bytes given
77             for a continuance is not the same number as were originally requested.
78              
79             Example:
80              
81             #This reads only 2 bytes, so read() will return undef.
82             $iof->read(10);
83              
84             #… wait for readiness if non-blocking …
85              
86             #XXX This die()s because we’re in the middle of trying to read
87             #10 bytes, not 4.
88             $iof->read(4);
89              
90             #If this completes the read (i.e., takes in 8 bytes), then it’ll
91             #return the full 10 bytes; otherwise, it’ll return undef again.
92             $iof->read(10);
93              
94             EINTR prompts a redo of the read operation. EAGAIN and EWOULDBLOCK (the same
95             error generally, but not always) prompt an undef return.
96             Any other failures prompt an instance of L to be
97             thrown.
98              
99             =head2 EMPTY READS
100              
101             This class’s C method will, by default, throw an instance of
102             L on an empty read. This is normal and logical
103             behavior in contexts (like L) where the data stream itself
104             indicates when no more data will come across. In such cases an empty read
105             is genuinely an error condition: it either means you’re reading past when
106             you should, or the other side prematurely went away.
107              
108             In some other cases, though, that empty read is the normal and expected way
109             to know that a filehandle/socket has no more data to read.
110              
111             If you prefer, then, you can call the C method to switch
112             to a different behavior, e.g.:
113              
114             $framed->allow_empty_read();
115              
116             my $frame = $framed->read(10);
117              
118             if (length $frame) {
119             #yay, we got a frame!
120             }
121             elsif (defined $frame) {
122             #no more data will come in, so let’s close up shop
123             }
124             else {
125             #undef means we just haven’t gotten as much data as we want yet;
126             #in this case, that means fewer than 10 bytes are available.
127             }
128              
129             Instead of throwing the aforementioned exception, C now returns
130             empty-string on an empty read. That means that you now have to distinguish
131             between multiple “falsey” states: undef for when the requested number
132             of bytes hasn’t yet arrived, and empty string for when no more bytes
133             will ever arrive. But it is also true now that the only exceptions thrown
134             are bona fide B, which will suit some applications better than the
135             default behavior.
136              
137             NB: If you want to be super-light, you can bring in IO::Framed::Read instead
138             of the full IO::Framed. (IO::Framed is already pretty lightweight, though.)
139              
140             =head1 ABOUT WRITES
141              
142             Writes for blocking I/O are straightforward: the system will always send
143             the entire buffer. The OS’s C won’t return until everything
144             meant to be written is written. Life is pleasant; life is simple. :)
145              
146             Non-blocking I/O is trickier. Not only can the OS’s C write
147             a subset of the data it’s given, but we also can’t know that the output
148             filehandle is ready right when we want it. This means that we have to queue up
149             our writes
150             then write them once we know (e.g., through C) that the filehandle
151             is ready. Each C call, then, enqueues one new buffer to write.
152              
153             Since it’s often useful to know when a payload has been sent,
154             C accepts an optional callback that will be executed immediately
155             after the last byte of the payload is written to the output filehandle.
156              
157             Empty out the write queue by calling C and looking for
158             a truthy response. (A falsey response means there is still data left in the
159             queue.) C gives you the number of queue items left
160             to write. (A partially-written item is treated the same as a fully-unwritten
161             one.)
162              
163             Note that, while it’s acceptable to activate and deactive the write queue,
164             the write queue must be empty in order to deactivate it. (You’ll get a
165             nasty, untyped exception otherwise!)
166              
167             C returns undef on EAGAIN and EWOULDBLOCK. It retries on EINTR,
168             so you should never actually see this error from this module.
169             Other errors prompt a thrown exception.
170              
171             NB: C and C return the object,
172             so you can instantiate thus:
173              
174             my $nb_writer = IO::Framed::Write->new($fh)->enable_write_queue();
175              
176             NB: If you want to be super-light, you can bring in IO::Framed::Write instead
177             of the full IO::Framed. (IO::Framed is already pretty lightweight, though.)
178              
179             =head1 CUSTOM READ & WRITE LOGIC
180              
181             As of version 0.04, you can override READ and WRITE methods with your
182             preferred logic. For example, in Linux you might prefer C rather than
183             C to avoid SIGPIPE, thus:
184              
185             package My::Framed;
186              
187             use parent qw( IO::Framed::Write );
188              
189             #Only these two arguments are given.
190             sub WRITE {
191             return send( $_[0], $_[1], Socket::MSG_NOSIGNAL );
192             }
193              
194             (NB: In *BSD OSes you can set SO_SIGNOPIPE on the filehandle instead.)
195              
196             You can likewise set C to achieve the same effect for reads.
197             (C receives all four arguments that C can consume.)
198              
199             B Unlike most inherited methods, C and C do
200             NOT receive the object instance. They must follow the same semantics as
201             Perl’s C and C: i.e., they must return the number
202             of bytes read/written, or return undef and set C<$!> appropriately on error.
203              
204             =head1 ERROR RESPONSES
205              
206             An empty read or any I/O error besides the ones mentioned previously
207             are indicated via an instance of one of the following exceptions.
208              
209             All exceptions subclass L, which itself
210             subclasses C.
211              
212             =over
213              
214             =item L
215              
216             =item L
217              
218             These both have an C property (cf. L’s accessor
219             method).
220              
221             =item L
222              
223             No properties. If this is thrown, your peer has probably closed the connection.
224             Unless you have called C to set an alternate behavior,
225             you might want to trap this exception if you call C.
226              
227             =back
228              
229             B This distribution doesn’t write to C<$!>. EAGAIN and EWOULDBLOCK on
230             C are ignored; all other errors are converted
231             to thrown exceptions.
232              
233             =cut
234              
235 3         28 use parent qw(
236             IO::Framed::Read
237             IO::Framed::Write
238 3     3   452 );
  3         342  
239              
240             sub new {
241 3     3 0 2578 my ( $class, $in_fh, $out_fh, $initial_buffer ) = @_;
242              
243 3         39 my $self = $class->SUPER::new( $in_fh, $initial_buffer );
244              
245 3   66     49 $self->{'_out_fh'} = $out_fh || $in_fh,
246              
247             return (bless $self, $class)->disable_write_queue();
248             }
249              
250             1;
251              
252             =head1 LEGACY CLASSES
253              
254             This distribution also includes the following B legacy classes:
255              
256             =over
257              
258             =item * IO::Framed::Write::Blocking
259              
260             =item * IO::Framed::Write::NonBlocking
261              
262             =item * IO::Framed::ReadWrite
263              
264             =item * IO::Framed::ReadWrite::Blocking
265              
266             =item * IO::Framed::ReadWrite::NonBlocking
267              
268             =back
269              
270             I’ll keep these in for the time being but eventually B remove them.
271             Please adjust any calling code that you might have.
272              
273             =head1 REPOSITORY
274              
275             L
276              
277             =head1 AUTHOR
278              
279             Felipe Gasper (FELIPE)
280              
281             =head1 COPYRIGHT
282              
283             Copyright 2017 by L
284              
285             =head1 LICENSE
286              
287             This distribution is released under the same license as Perl.
288              
289             =cut