File Coverage

blib/lib/Protocol/DBus/Client.pm
Criterion Covered Total %
statement 50 66 75.7
branch 7 18 38.8
condition 3 8 37.5
subroutine 15 18 83.3
pod 7 8 87.5
total 82 118 69.4


line stmt bran cond sub pod time code
1             package Protocol::DBus::Client;
2              
3 5     5   636776 use strict;
  5         22  
  5         142  
4 5     5   24 use warnings;
  5         22  
  5         146  
5              
6             =encoding utf-8
7              
8             =head1 NAME
9              
10             Protocol::DBus::Client
11              
12             =head1 SYNOPSIS
13              
14             my $dbus = Protocol::DBus::Client::system();
15              
16             $dbus->initialize();
17              
18             =head1 DESCRIPTION
19              
20             This is the end class for use in DBus client applications. It subclasses
21             L.
22              
23             B This module will automatically send a “Hello” message after
24             authentication completes. That message’s response will be processed
25             automatically. Because this is part of the protocol’s handshake
26             logic rather than something useful for callers, it is abstracted away from
27             the caller. It is neither necessary nor productive for callers to send a
28             “Hello” message.
29              
30             =cut
31              
32 5     5   24 use parent 'Protocol::DBus::Peer';
  5         10  
  5         25  
33              
34 5     5   2348 use Protocol::DBus::Authn;
  5         14  
  5         150  
35 5     5   2075 use Protocol::DBus::Connect;
  5         10  
  5         154  
36 5     5   2032 use Protocol::DBus::Path;
  5         14  
  5         2590  
37              
38             =head1 STATIC FUNCTIONS
39              
40             =head2 system()
41              
42             Creates an instance of this class that includes a connection to the
43             system’s message bus.
44              
45             This does not do authentication; you’ll need to do that via the class’s
46             methods.
47              
48             =cut
49              
50             sub system {
51 1     1 1 979 my @addrs = Protocol::DBus::Path::system_message_bus();
52              
53 1         4 return _create_local(@addrs);
54             }
55              
56             =head2 login_session()
57              
58             Like C but for the login session’s message bus.
59              
60             =cut
61              
62             sub login_session {
63 0     0 1 0 my @addrs = Protocol::DBus::Path::login_session_message_bus();
64              
65 0 0       0 if (!@addrs) {
66 0         0 die "Failed to identify login system message bus!";
67             }
68              
69 0         0 return _create_local(@addrs);
70             }
71              
72             sub _create_local {
73 1     1   3 my ($addr) = @_;
74 1         4 my $socket = Protocol::DBus::Connect::create_socket($addr);
75              
76 0         0 return __PACKAGE__->new(
77             socket => $socket,
78             authn_mechanism => 'EXTERNAL',
79             );
80             }
81              
82             #----------------------------------------------------------------------
83              
84             =head1 METHODS
85              
86             =head2 $done_yn = I->initialize()
87              
88             This returns truthy once the connection is ready to use and falsy until then.
89             In blocking I/O contexts the call will block.
90              
91             Note that this automatically handles D-Bus’s initial C message and
92             its response.
93              
94             Previously this function was called C and did not wait for
95             the C message’s response. The older name is retained
96             as an alias for backward compatibility.
97              
98             =cut
99              
100             sub initialize {
101 1     1 1 44 my ($self) = @_;
102              
103 1 50       13 if ($self->{'_authn'}->go()) {
104 1   33     31 $self->{'_sent_hello'} ||= do {
105             $self->send_call(
106             path => '/org/freedesktop/DBus',
107             interface => 'org.freedesktop.DBus',
108             destination => 'org.freedesktop.DBus',
109             member => 'Hello',
110 1     1   36 )->then( sub { $self->{'_connection_name'} = $_[0]->get_body()->[0]; } );
  1         105  
111             };
112              
113 1 50       55 if (!$self->{'_connection_name'}) {
114             GET_MESSAGE: {
115 1 50       3 if (my $msg = $self->SUPER::get_message()) {
  2         21  
116 2 100       10 return 1 if $self->{'_connection_name'};
117              
118 1         2 push @{ $self->{'_pending_received_messages'} }, $msg;
  1         6  
119              
120 1         4 redo GET_MESSAGE;
121             }
122             }
123             }
124             }
125              
126 0         0 return 0;
127             }
128              
129             *do_authn = *initialize;
130              
131             #----------------------------------------------------------------------
132              
133             =head2 $yn = I->init_pending_send()
134              
135             This indicates whether there is data queued up to send for the initialization.
136             Only useful with non-blocking I/O.
137              
138             This function was previously called C; the former
139             name is retained for backward compatibility.
140              
141             =cut
142              
143             sub init_pending_send {
144 0     0 1 0 my ($self) = @_;
145              
146 0 0       0 if ($self->{'_connection_name'}) {
147 0         0 die "Don’t call this after initialize() is done!";
148             }
149              
150 0 0       0 if ($self->{'_sent_hello'}) {
151 0         0 return $self->pending_send();
152             }
153              
154 0         0 return $self->{'_authn'}->pending_send();
155             }
156              
157             *authn_pending_send = \*init_pending_send;
158              
159             #----------------------------------------------------------------------
160              
161             =head2 $yn = I->supports_unix_fd()
162              
163             Boolean that indicates whether this client supports UNIX FD passing.
164              
165             =cut
166              
167             sub supports_unix_fd {
168 0     0 1 0 my ($self) = @_;
169              
170 0         0 return $self->{'_authn'}->negotiated_unix_fd();
171             }
172              
173             #----------------------------------------------------------------------
174              
175             =head2 $msg = I->get_message()
176              
177             Same as in the base class, but for clients the initial “Hello” message and
178             its response are abstracted
179              
180             =cut
181              
182             sub get_message {
183 1     1 1 49 my ($self) = @_;
184              
185 1 50       7 die "initialize() is not finished!" if !$self->{'_connection_name'};
186              
187 1 50 33     14 if ($self->{'_pending_received_messages'} && @{ $self->{'_pending_received_messages'} }) {
  1         7  
188 1         4 return shift @{ $self->{'_pending_received_messages'} };
  1         5  
189             }
190              
191 5     5   36 no warnings 'redefine';
  5         11  
  5         586  
192 0         0 *get_message = Protocol::DBus::Peer->can('get_message');
193              
194 0         0 return $_[0]->get_message();
195             }
196              
197             =head2 $name = I->get_unique_bus_name()
198              
199             Returns the connection’s unique bus name.
200              
201             C is a historical alias for this method.
202              
203             =cut
204              
205             sub get_unique_bus_name {
206 1   50 1 1 45 return $_[0]->{'_connection_name'} || die 'No connection name known yet!';
207             }
208              
209             BEGIN {
210 5     5   502 *get_connection_name = *get_unique_bus_name;
211             }
212              
213             # undocumented for now
214             sub new {
215 1     1 0 851923 my ($class, %opts) = @_;
216              
217             my $authn = Protocol::DBus::Authn->new(
218             socket => $opts{'socket'},
219 1         129 mechanism => $opts{'authn_mechanism'},
220             );
221              
222 1         86 my $self = $class->SUPER::new( $opts{'socket'} );
223              
224 1         12 $self->{'_authn'} = $authn;
225              
226 1         8 return $self;
227             }
228              
229             1;