File Coverage

blib/lib/Protocol/Sys/Virt/Transport.pm
Criterion Covered Total %
statement 14 152 9.2
branch 0 70 0.0
condition 0 37 0.0
subroutine 5 13 38.4
pod 4 4 100.0
total 23 276 8.3


line stmt bran cond sub pod time code
1             ####################################################################
2             #
3             # This file was generated using XDR::Parse version v1.0.1,
4             # XDR::Gen version 1.1.2 and LibVirt version v12.1.0
5             #
6             # Don't edit this file, use the source template instead
7             #
8             # ANY CHANGES HERE WILL BE LOST !
9             #
10             ####################################################################
11              
12              
13 1     1   1412 use v5.14;
  1         3  
14 1     1   4 use warnings;
  1         1  
  1         69  
15              
16             package Protocol::Sys::Virt::Transport v12.1.0;
17              
18 1     1   4 use Carp qw(croak);
  1         2  
  1         67  
19 1     1   5 use Log::Any qw($log);
  1         1  
  1         16  
20              
21 1     1   222 use Protocol::Sys::Virt::Transport::XDR;
  1         2  
  1         1536  
22              
23             my $msgs = 'Protocol::Sys::Virt::Transport::XDR';
24              
25             sub new {
26 0     0 1   my ($class, %args) = @_;
27             return bless {
28             buf => '',
29             fds => undef,
30             expect => 'START', # first state of the state machine...
31             want => -1,
32             need_length => 4,
33             need_type => 'data',
34             role => $args{role},
35             serial => 1,
36             prog_cb => {},
37             on_send => $args{on_send},
38 0           }, $class;
39             };
40              
41             sub register {
42 0     0 1   my ($self, $prog, $version, $callbacks) = @_;
43 0           $self->{prog_cb}->{$prog} = $callbacks;
44              
45             return sub {
46 0     0     return $self->_send( $prog, $version, @_ );
47 0           };
48             }
49              
50             my @dispatch = qw(
51             on_call on_reply on_message on_stream
52             on_call on_reply on_stream );
53              
54              
55             sub _dispatch {
56 0     0     my ($self) = @_;
57 0           my $data = $self->{payload};
58 0           my $fds = $self->{fds};
59 0           my $hdr = $self->{hdr};
60 0           my $status = $hdr->{status};
61 0           my $type = $hdr->{type};
62 0           my $prog = $hdr->{prog};
63              
64 0 0         if ($status == $msgs->OK) {
    0          
    0          
65 0 0 0       if ($type < 0 or $type > $#dispatch) {
66 0           croak $log->fatal("Unsupported frame type $type");
67             }
68              
69 0           my $hole;
70 0 0         if ($type == $msgs->STREAM_HOLE) {
71 0           my $idx = 0;
72 0           $msgs->deserialize_StreamHole( $hole, $idx, $self->{buf} );
73 0           $self->{buf} = substr( $self->{buf}, $idx );
74              
75 0           $data = undef;
76             }
77 0           $log->trace("Invoking callback $dispatch[$type] on program $prog");
78 0           return $self->{prog_cb}->{$prog}->{$dispatch[$type]}->(
79             header => $hdr,
80             data => $data,
81             fds => $fds,
82             hole => $hole
83             );
84             }
85             elsif ($status == $msgs->ERROR) {
86 0 0 0       if ($type == $msgs->STREAM
87             and $self->{role} eq 'server') { # client message
88             # no payload
89 0           return $self->{prog_cb}->{$prog}->{on_stream}->(
90             header => $hdr,
91             );
92             }
93              
94             #deserialize the server error...
95 0           my $err;
96 0           my $idx = 0;
97 0           $msgs->deserialize_Error( $err, $idx, $data );
98 0 0 0       if ($type == $msgs->REPLY
      0        
      0        
99             or $type == $msgs->STREAM
100             or $type == $msgs->STREAM_HOLE
101             or $type == $msgs->REPLY_WITH_FDS) {
102 0           $log->trace("Invoking callback $dispatch[$type] on program $prog");
103 0           return $self->{prog_cb}->{$prog}->{$dispatch[$type]}->(
104             header => $hdr,
105             error => $err,
106             );
107             }
108             else {
109 0           croak $log->fatal( "Status ERROR not supported on frame type $type" );
110             }
111             }
112             elsif ($status == $msgs->CONTINUE) {
113 0 0         if ($type == $msgs->STREAM) {
    0          
114 0           return $self->{prog_cb}->{$prog}->{on_stream}->(
115             header => $hdr,
116             data => $data
117             );
118             }
119             elsif ($type == $msgs->STREAM_HOLE) {
120 0           my $hole;
121 0           my $idx = 0;
122 0           $msgs->deserialize_StreamHole( $hole, $idx, $self->{buf} );
123 0           $log->trace("Invoking callback $dispatch[$type] on program $prog");
124 0           return $self->{prog_cb}->{$prog}->{on_stream}->(
125             header => $hdr,
126             hole => $hole
127             );
128             }
129             else {
130 0           croak $log->fatal( "Status CONTINUE not supported on frame type $type" );
131             }
132             }
133             else {
134 0           croak $log->fatal( "Unsupported 'status' value ($status)" );
135             }
136              
137             # unreachable
138             }
139              
140             # state machine
141             #
142             # states:
143             # START (nothing happened yet)
144             # FRAMELEN (awaiting 4 bytes of data)
145             # FRAMEDATA (awaiting remaining data)
146             # FD (awaiting file descriptors)
147              
148             sub _receive {
149 0     0     my ($self, $data) = @_;
150 0           my @dispatch_values = ();
151              
152 0 0         if ($data) {
153 0 0         if ($self->{expect} eq 'FD') {
154 0           push @{ $self->{fds} }, $data;
  0            
155             }
156             else {
157 0           $self->{buf} .= $data;
158             }
159             }
160              
161 0           while (1) {
162 0 0         if ($self->{expect} eq 'START') {
163 0           $self->{want} = 4;
164 0           $self->{want_fds} = 0;
165 0           $self->{fds} = undef;
166 0           $self->{payload} = '';
167              
168 0           $self->{expect} = 'FRAMELEN';
169             }
170 0 0         if ($self->{expect} eq 'FRAMELEN') {
171 0           my $len = length($self->{buf});
172 0 0         if ($self->{want} > $len) {
173 0           $self->{need_length} = $self->{want} - $len;
174 0           $self->{need_type} = 'data';
175 0           last;
176             }
177 0           $self->{want} = unpack('L>', $self->{buf} );
178 0 0         if ($self->{want} < ($msgs->LEN_MAX
179             + $msgs->HEADER_MAX)) {
180 0           croak $log->fatal(
181             "Received message too short (length: $self->{want})" );
182             }
183 0 0         if ($self->{want} > $msgs->STRING_MAX) {
184 0           croak $log->fatal(
185             "Received message too big (length: $self->{want})" );
186             }
187              
188 0           $self->{expect} = 'FRAMEDATA';
189             }
190 0 0         if ($self->{expect} eq 'FRAMEDATA') {
191 0           my $len = length($self->{buf});
192 0 0         if ($self->{want} > $len) {
193 0           $self->{need_length} = $self->{want} - $len;
194 0           $self->{need_type} = 'data';
195 0           last;
196             }
197              
198             # we have our frame
199 0           my $idx = 4;
200 0           my $hdr = {};
201 0           $msgs->deserialize_Header( $hdr, $idx, $self->{buf} );
202 0           $self->{hdr} = $hdr;
203              
204 0           my $type = $hdr->{type};
205 0           my $status = $hdr->{status};
206 0 0 0       if ($status == $msgs->OK
      0        
207             and ($type == $msgs->CALL_WITH_FDS
208             or $type == $msgs->REPLY_WITH_FDS)) {
209             $self->{want_fds} =
210 0           unpack('L>', substr( $self->{buf}, $idx, 4 ));
211 0           $self->{fds} = [];
212 0           $idx += 4;
213              
214 0           $self->{expect} = 'FD';
215             }
216             $self->{payload} =
217 0           substr( $self->{buf}, $idx, $self->{want} - $idx );
218 0           $self->{buf} = '' . substr( $self->{buf}, $self->{want} );
219             }
220 0 0         if ($self->{expect} eq 'FD') {
221 0           my $len = scalar( @{ $self->{fds} } );
  0            
222 0 0         if ($self->{want_fds} > $len) {
223 0           $self->{need_length} = $self->{want_fds} - $len;
224 0           $self->{need_type} = 'fd';
225 0           last;
226             }
227             }
228             # we have our frame *and* (optionally) FDs
229              
230 0           my $dv = $self->_dispatch;
231 0 0         push @dispatch_values, $dv if defined $dv;
232              
233 0           $self->{expect} = 'START';
234             }
235              
236 0           return @dispatch_values;
237             }
238              
239              
240             sub need {
241 0     0 1   my $self = shift;
242 0           return ($self->{need_length}, $self->{need_type});
243             }
244              
245             sub receive {
246 0     0 1   my ($self, $data, %args) = @_;
247              
248 0           return $self->_receive($data, %args);
249             }
250              
251             sub _send {
252 0     0     my ($self, $prog, $version, $proc, $type, %args) = @_;
253              
254 0           my $hdr = pack('L>', 0);
255 0           my $serial;
256 0           my $idx = length($hdr);
257 0   0       my $status = $args{status} // $msgs->OK;
258 0 0 0       if ($type == $msgs->CALL
    0          
    0          
259             or $type == $msgs->CALL_WITH_FDS) {
260 0           $serial = $self->{serial}++;
261             }
262             elsif ($type == $msgs->MESSAGE) {
263 0           $serial = 0;
264             }
265             elsif (defined $args{serial}) {
266 0           $serial = $args{serial};
267             }
268             else {
269 0           croak $log->fatal( "Missing 'serial' argument for frame type $type" );
270             }
271 0           $msgs->serialize_Header(
272             {
273             prog => $prog,
274             vers => $version,
275             proc => $proc,
276             type => $type,
277             serial => $serial,
278             status => $status,
279             },
280             $idx, $hdr );
281              
282 0 0         if ($status == $msgs->OK) {
    0          
    0          
283 0 0 0       if ($type == $msgs->CALL_WITH_FDS
284             or $type == $msgs->REPLY_WITH_FDS) {
285             # Add FD count before the call arguments data
286             }
287              
288 0   0       my $length = length($hdr) + length($args{data} // '');
289 0 0         croak "Message too large: $length" if $length > $msgs->MAX;
290              
291 0           substr($hdr, 0, 4) = pack('L>', $length);
292 0           return $self->{on_send}->( $serial, $hdr, $args{data} );
293             ###BUG: Send FDs
294             }
295             elsif ($status == $msgs->ERROR) {
296 0           my $payload = '';
297 0 0 0       unless ($type == $msgs->STREAM
298             and $self->{role} eq 'client') { # client message
299 0           my $i = 0;
300 0           $msgs->serialize_Error( $args{error}, $i, $payload );
301             }
302              
303 0           my $length = length($hdr) + length($payload);
304 0 0         croak "Message too large: $length" if $length > $msgs->MAX;
305              
306 0           substr($hdr, 0, 4) = pack('L>', $length);
307 0           return $self->{on_send}->( $serial, $hdr, $payload );
308             }
309             elsif ($status == $msgs->CONTINUE) {
310 0           my $payload = '';
311 0 0         if ($type == $msgs->STREAM_HOLE) {
    0          
312 0           my $i = 0;
313 0           $msgs->serialize_StreamHole( $args{hole}, $i, $payload );
314             }
315             elsif ($type == $msgs->STREAM) {
316 0           $payload = $args{data};
317             }
318             else {
319 0           croak $log->fatal( "Unsupported frame type $type with status CONTINUE" );
320             }
321              
322 0   0       my $length = length($hdr) + length($payload // '');
323 0 0         croak "Message too large: $length" if $length > $msgs->MAX;
324              
325 0           substr($hdr, 0, 4) = pack('L>', $length);
326 0           return $self->{on_send}->( $serial, $hdr, $payload );
327             }
328             else {
329 0           croak $log->fatal( "Unsupported frame status $status" );
330             }
331              
332             # unreachable
333             }
334              
335             1;
336              
337             __END__