File Coverage

blib/lib/Protocol/DBus/Peer.pm
Criterion Covered Total %
statement 59 78 75.6
branch 6 16 37.5
condition 7 11 63.6
subroutine 14 21 66.6
pod 11 12 91.6
total 97 138 70.2


line stmt bran cond sub pod time code
1             package Protocol::DBus::Peer;
2              
3 5     5   2219 use strict;
  5         10  
  5         136  
4 5     5   25 use warnings;
  5         19  
  5         146  
5              
6             =encoding utf-8
7              
8             =head1 NAME
9              
10             Protocol::DBus::Peer - base class for a D-Bus peer
11              
12             =head1 SYNOPSIS
13              
14             $dbus->send_call(
15             interface => 'org.freedesktop.DBus.Properties',
16             member => 'GetAll',
17             signature => 's',
18             path => '/org/freedesktop/DBus',
19             destination => 'org.freedesktop.DBus',
20             body => [ 'org.freedesktop.DBus' ],
21             on_return => sub { my ($msg) = @_ },
22             );
23              
24             my $msg = $dbus->get_message();
25              
26             # Same pattern as the IO::Handle method.
27             $dbus->blocking(0);
28              
29             my $fileno = $dbus->fileno();
30              
31             $dbus->flush_write_queue() if $dbus->pending_send();
32              
33             # I’m not sure why you’d want to do this, but …
34             $dbus->big_endian();
35              
36             =head1 DESCRIPTION
37              
38             This class contains D-Bus logic that is useful in both client and
39             server contexts. (Currently this distribution does not include a server
40             implementation.)
41              
42             =cut
43              
44 5     5   2298 use Call::Context;
  5         1870  
  5         151  
45              
46 5     5   2317 use Protocol::DBus::Message;
  5         15  
  5         152  
47 5     5   2065 use Protocol::DBus::Parser;
  5         15  
  5         141  
48 5     5   2105 use Protocol::DBus::WriteMsg;
  5         14  
  5         5033  
49              
50             #----------------------------------------------------------------------
51              
52             =head1 METHODS
53              
54             =head2 $msg = I->get_message()
55              
56             This returns a single instace of L, or undef if
57             no message is available. It will also fire the appropriate “on_return”
58             method on METHOD_RETURN messages.
59              
60             The backend I/O logic reads data in chunks; thus, if there is a message
61             already available in the read buffer, no I/O is done. If you’re doing
62             non-blocking I/O then it is thus B that, every time the DBus socket
63             is readable, you call this function until undef is returned.
64              
65             =cut
66              
67             sub get_message {
68 3     3 1 37 my $msg = $_[0]->{'_parser'}->get_message();
69              
70 3 50       11 if ($msg) {
71 3 100       14 if (my $serial = $msg->get_header('REPLY_SERIAL')) {
72 1 50       4 if (my $cb = delete $_[0]->{'_on_return'}{$serial}) {
73 1         5 $cb->($msg);
74             }
75             }
76             }
77              
78 3         14 return $msg;
79             }
80              
81             #----------------------------------------------------------------------
82              
83             =head2 I->flush_write_queue()
84              
85             Same as L’s method of the same name.
86              
87             =cut
88              
89             sub flush_write_queue {
90 0 0   0 1 0 if ($_[0]->{'_io'}->get_write_queue_count()) {
91 0         0 return $_[0]->{'_io'}->flush_write_queue();
92             }
93              
94 0         0 return 1;
95             }
96              
97             #----------------------------------------------------------------------
98              
99             =head2 I->send_call( %OPTS )
100              
101             Send a METHOD_CALL message.
102              
103             %OPTS are C, C, C, C, C,
104             C, and C. These do as you’d expect, with the following
105             caveats:
106              
107             =over
108              
109             =item * C, if given, must be an array reference. See
110             L for a discussion of how to map between D-Bus and
111             Perl.
112              
113             =item * The C callback receives the server’s response
114             message (NB: either METHOD_RETURN or ERROR) as argument.
115              
116             =back
117              
118             =cut
119              
120             sub send_call {
121 1     1 1 23 my ($self, %opts) = @_;
122              
123 1         11 my $cb = delete $opts{'on_return'};
124              
125 1         19 my $ret = $self->_send_msg(
126             %opts,
127             type => 'METHOD_CALL',
128             );
129              
130 1 50       45 if ($cb) {
131 1         2 my $serial = $self->{'_last_sent_serial'};
132 1         5 $self->{'_on_return'}{$serial} = $cb;
133             }
134              
135 1         6 return $ret;
136             }
137              
138             =head2 I->send_return( $ORIG_MSG, %OPTS )
139              
140             Send a METHOD_RETURN message.
141              
142             Arguments are similar to C except for the header differences
143             that the D-Bus specification describes. Also:
144              
145             =over
146              
147             =item * C is taken from the $ORIG_MSG. (Behavior is
148             undefined if this parameter is given directly.)
149              
150             =item * There is no C parameter.
151              
152             =back
153              
154             =cut
155              
156             sub send_return {
157 1     1 1 60 my ($self, $orig_msg, @opts_kv) = @_;
158              
159 1         6 return $self->_send_msg(
160             _response_fields_from_orig_msg($orig_msg, \@opts_kv),
161             type => 'METHOD_RETURN',
162             );
163             }
164              
165             =head2 I->send_error( $ORIG_MSG, %OPTS )
166              
167             Like C, but sends an error instead. The
168             C parameter is required.
169              
170             =cut
171              
172             sub send_error {
173 0     0 1 0 my ($self, $orig_msg, @opts_kv) = @_;
174              
175 0         0 return $self->_send_msg(
176             _response_fields_from_orig_msg($orig_msg, \@opts_kv),
177             type => 'ERROR',
178             );
179             }
180              
181             sub _response_fields_from_orig_msg {
182              
183             return (
184              
185             # This has to honor a passed “destination”
186             # so that we can implement a D-Bus server in tests.
187             destination => $_[0]->get_header('SENDER'),
188              
189 1     1   5 @{ $_[1] },
  1         5  
190              
191             # Reject callers’ attempts to set this one.
192             reply_serial => $_[0]->get_serial(),
193             );
194             }
195              
196             =head2 I->send_signal( %OPTS )
197              
198             Like C but sends a signal rather than a method call.
199             There is no C parameter.
200              
201             =cut
202              
203             sub send_signal {
204 1     1 1 986 my ($self, @opts_kv) = @_;
205              
206 1         7 return $self->_send_msg(
207             @opts_kv,
208             type => 'SIGNAL',
209             );
210             }
211              
212             #----------------------------------------------------------------------
213              
214             =head2 I->big_endian()
215              
216             Same interface as C, but this sets/gets/toggles whether to send
217             big-endian messages instead of little-endian.
218              
219             By default this library uses the system’s native byte order, so you probably
220             have little need for this function.
221              
222             =cut
223              
224             sub big_endian {
225 0     0 1 0 my ($self) = @_;
226              
227 0 0       0 if (@_ > 0) {
228 0         0 my $old = $self->{'_big_endian'};
229 0         0 $self->{'_big_endian'} = !!$_[1];
230              
231 0 0       0 $self->{'_to_str_fn'} = 'to_string_' . ($_[1] ? 'be' : 'le');
232              
233 0         0 return $self->{'_big_endian'};
234             }
235              
236 0         0 return !!$self->{'_big_endian'};
237             }
238              
239             #----------------------------------------------------------------------
240              
241             =head2 I->preserve_variant_signatures()
242              
243             Same interface as C, but when this is enabled
244             variants are given as two-member array references ([ signature => value ]),
245             blessed as C instances.
246              
247             For most Perl applications this is probably counterproductive.
248              
249             =cut
250              
251             sub preserve_variant_signatures {
252 0     0 1 0 my $self = shift;
253              
254 0         0 return $self->{'_parser'}->preserve_variant_signatures(@_);
255             }
256              
257             #----------------------------------------------------------------------
258              
259             =head2 I->blocking()
260              
261             Same interface as L’s method of the same name.
262              
263             =cut
264              
265             sub blocking {
266 0     0 1 0 my $self = shift;
267              
268 0         0 return $self->{'_socket'}->blocking(@_);
269             }
270              
271             #----------------------------------------------------------------------
272              
273             =head2 I->fileno()
274              
275             Returns the connection socket’s file descriptor.
276              
277             =cut
278              
279             sub fileno {
280 0     0 1 0 return fileno $_[0]->{'_socket'};
281             }
282              
283             #----------------------------------------------------------------------
284              
285             =head2 I->pending_send()
286              
287             Returns a boolean that indicates whether there is data queued up to send
288             to the server.
289              
290             =cut
291              
292             sub pending_send {
293 0     0 1 0 return !!$_[0]->{'_io'}->get_write_queue_count();
294             }
295              
296             #----------------------------------------------------------------------
297              
298             # undocumented
299             sub new {
300 2     2 0 868565 my ($class, $socket) = @_;
301              
302 2         46 my $self = bless { _socket => $socket }, $class;
303              
304 2         61 $self->_set_up_peer_io( $socket );
305              
306 2         7 return $self;
307             }
308              
309             #----------------------------------------------------------------------
310              
311             sub _set_up_peer_io {
312 2     2   19 my ($self, $socket) = @_;
313              
314 2         144 $self->{'_io'} = Protocol::DBus::WriteMsg->new( $socket )->enable_write_queue();
315 2         194 $self->{'_parser'} = Protocol::DBus::Parser->new( $socket );
316              
317 2         19 return;
318             }
319              
320             sub _send_msg {
321 3     3   56 my ($self, %opts) = @_;
322              
323 3         20 my ($type, $body_ar, $flags) = delete @opts{'type', 'body', 'flags'};
324              
325             my @hargs = map {
326 3         15 my $k = $_;
  14         21  
327 14         27 $k =~ tr;
328 14         38 ( $k => $opts{$_} );
329             } keys %opts;
330              
331 3         18 my $serial = ++$self->{'_last_sent_serial'};
332              
333 3         45 my $msg = Protocol::DBus::Message->new(
334             type => $type,
335             hfields => \@hargs,
336             flags => $flags,
337             body => $body_ar,
338             serial => $serial,
339             );
340              
341             # Use native byte order by default.
342 3   100     52 $self->{'_endian'} ||= (pack 'n', 1) eq (pack 'l', 1) ? 'be' : 'le';
343              
344 3   66     38 $self->{'_to_str_fn'} ||= "to_string_$self->{'_endian'}";
345              
346 3         62 my ($buf_sr, $fds_ar) = $msg->can($self->{'_to_str_fn'})->($msg);
347              
348 3 50 66     44 if ($fds_ar && @$fds_ar && !$self->supports_unix_fd()) {
      33        
349 0         0 die "Cannot send file descriptors without UNIX FD support!";
350             }
351              
352 3         20 $self->{'_io'}->enqueue_message( $buf_sr, $fds_ar );
353              
354 3         25 return $self->{'_io'}->flush_write_queue();
355             }
356              
357             1;