File Coverage

blib/lib/Protocol/DBus/Parser.pm
Criterion Covered Total %
statement 54 75 72.0
branch 17 46 36.9
condition 2 14 14.2
subroutine 9 10 90.0
pod 0 3 0.0
total 82 148 55.4


line stmt bran cond sub pod time code
1             package Protocol::DBus::Parser;
2              
3 5     5   31 use strict;
  5         10  
  5         146  
4 5     5   25 use warnings;
  5         10  
  5         114  
5              
6 5     5   25 use Protocol::DBus::Marshal ();
  5         10  
  5         56  
7 5     5   20 use Protocol::DBus::Message ();
  5         11  
  5         174  
8              
9 5     5   29 use constant SINGLE_UNIX_FD_CMSGHDR => (0, 0, pack 'I!');
  5         9  
  5         335  
10              
11 5     5   37 use constant _LE_INIT_UNPACK => 'x4 V x4 V';
  5         11  
  5         266  
12 5     5   30 use constant _BE_INIT_UNPACK => 'x4 N x4 N';
  5         10  
  5         4253  
13              
14             sub new {
15 2     2 0 33 my ($class, $socket) = @_;
16              
17 2         85 return bless { _s => $socket, _buf => q<> }, $class;
18             }
19              
20             sub get_message {
21 3     3 0 36 my ($self) = @_;
22              
23 3         22 my $msg;
24              
25 3 50       55 if (!$self->{'_bodysz'}) {
26 3 50 0     15273 if (defined recv( $self->{'_s'}, my $peek, 16, Socket::MSG_PEEK() )) {
    0          
27 3 50       36 if (!length $peek) {
    50          
28 0         0 die "D-Bus connection closed unexpectedly!";
29             }
30             elsif ( 16 == length $peek ) {
31 3 50       32 @{$self}{'_bodysz', '_hdrsz'} = unpack(
  3         34  
32             (0 == index($peek, 'B')) ? _BE_INIT_UNPACK() : _LE_INIT_UNPACK(),
33             $peek,
34             );
35              
36 3         52 Protocol::DBus::Pack::align( $self->{'_hdrsz'}, 8 );
37              
38 3         23 $self->{'_msgsz'} = 16 + $self->{'_hdrsz'} + $self->{'_bodysz'};
39             }
40             }
41             elsif (!$!{'EAGAIN'} && !$!{'EWOULDBLOCK'}) {
42 0         0 die "recv(): $!";
43             }
44             }
45              
46 3 50 33     60 if (defined $self->{'_bodysz'} && !defined $self->{'_unix_fds'}) {
47 3 50 0     58 if (defined recv( $self->{'_s'}, my $full_hdr, 16 + $self->{'_hdrsz'}, Socket::MSG_PEEK() )) {
    0          
48 3 50       19 if ( length($full_hdr) == 16 + $self->{'_hdrsz'} ) {
49 3         55 my ($hdr) = Protocol::DBus::Message::Header::parse_simple(\$full_hdr);
50              
51 3   50     28 $self->{'_unix_fds'} = $hdr->[6]{ Protocol::DBus::Message::Header::FIELD()->{'UNIX_FDS'} } || 0;
52              
53 3         8 $self->{'_pending_unix_fds'} = $self->{'_unix_fds'};
54              
55 3         8 my $body_sig = $hdr->[6]{ Protocol::DBus::Message::Header::FIELD()->{'SIGNATURE'} };
56              
57 3 100       31 if ($hdr->[4]) {
58 2 50       13 die "No SIGNATURE header field!" if !defined $body_sig;
59             }
60             }
61             }
62             elsif (!$!{'EAGAIN'} && !$!{'EWOULDBLOCK'}) {
63 0         0 die "recv(): $!";
64             }
65             }
66              
67 3 50       13 if (defined $self->{'_unix_fds'}) {
68              
69 3         10 my $needed_bytes = $self->{'_msgsz'} - length $self->{'_buf'};
70              
71 3         5 my $got;
72              
73 3 50       10 if ($self->{'_unix_fds'}) {
74 0         0 my $msg = Socket::MsgHdr->new(
75             buflen => $needed_bytes,
76             );
77              
78             # The unix FDs might arrive in a single control
79             # message, as individual control messages, or as
80             # some combination thereof. There is no way to know.
81             # So plan for the worst, and assume each unix FD is
82             # in its own control.
83 0         0 $msg->cmsghdr( (SINGLE_UNIX_FD_CMSGHDR()) x $self->{'_pending_unix_fds'} );
84              
85 0         0 $got = Socket::MsgHdr::recvmsg( $self->{'_s'}, $msg );
86 0 0       0 if (defined $got) {
87              
88 0 0       0 if ($self->{'_pending_unix_fds'}) {
89 0         0 require Protocol::DBus::Parser::UnixFDs;
90 0         0 push @{ $self->{'_filehandles'} }, Protocol::DBus::Parser::UnixFDs::extract_from_msghdr($msg);
  0         0  
91 0         0 $self->{'_pending_unix_fds'} = $self->{'_unix_fds'} - @{ $self->{'_filehandles'} };
  0         0  
92             }
93              
94 0         0 $self->{'_buf'} .= $msg->buf();
95             }
96             }
97             else {
98             $got = sysread(
99             $self->{'_s'},
100             $self->{'_buf'},
101             $needed_bytes,
102 3         101 length $self->{'_buf'},
103             );
104             }
105              
106 3 50 0     25 if (defined $got) {
    0          
107 3 50       11 if ($got >= $needed_bytes) {
    0          
108 3 50       10 local $Protocol::DBus::Marshal::PRESERVE_VARIANT_SIGNATURES = 1 if $self->{'_preserve_variant_signatures'};
109              
110             # This clears out the buffer .. it should??
111 3         38 my $msg = Protocol::DBus::Message->parse( \$self->{'_buf'}, delete $self->{'_filehandles'} );
112              
113 3 50       15 die "Not enough bytes??" if !$msg;
114              
115 3         7 delete @{$self}{'_bodysz', '_unix_fds'};
  3         10  
116              
117 3         14 return $msg;
118             }
119             elsif (!$got) {
120 0           die "Peer stopped writing!";
121             }
122             }
123             elsif (!$!{'EAGAIN'} && !$!{'EWOULDBLOCK'}) {
124 0           die "recv(): $!";
125             }
126             }
127              
128 0           return undef;
129             }
130              
131             sub preserve_variant_signatures {
132 0     0 0   my $self = shift;
133              
134 0 0         if (@_) {
135 0           $self->{'_preserve_variant_signatures'} = !!$_[0];
136             }
137              
138 0           return !!$self->{'_preserve_variant_signatures'};
139             }
140              
141             1;