File Coverage

blib/lib/App/ReslirpTunnel/RPC.pm
Criterion Covered Total %
statement 18 56 32.1
branch 0 8 0.0
condition 0 2 0.0
subroutine 6 12 50.0
pod 0 5 0.0
total 24 83 28.9


line stmt bran cond sub pod time code
1             package App::ReslirpTunnel::RPC;
2              
3 1     1   657 use Socket::MsgHdr;
  1         2074  
  1         11  
4 1     1   86 use IO::Socket::UNIX;
  1         2  
  1         9  
5              
6 1     1   682 use strict;
  1         3  
  1         28  
7 1     1   5 use warnings;
  1         3  
  1         88  
8 1     1   8 use JSON::PP;
  1         3  
  1         82  
9 1     1   7 use POSIX;
  1         15  
  1         11  
10              
11             sub new {
12 0     0 0   my $class = shift;
13 0           my $socket = shift;
14 0           my $self = \$socket;
15 0           bless $self, $class;
16 0           return $self;
17             }
18              
19             sub recv_packet {
20 0     0 0   my $self = shift;
21 0           my $header = $self->_read_bytes(4);
22 0           my $len = unpack("N", $header);
23 0           my $data = $self->_read_bytes($len);
24 0           utf8::decode($data);
25             # warn "Packet received: $data\n";
26 0           my $r = JSON::PP::decode_json($data);
27 0           return $r;
28             }
29              
30             sub _read_bytes {
31 0     0     my ($self, $len) = @_;
32 0           my $buf = "";
33              
34 0           while (length $buf < $len) {
35 0           my $n = sysread($$self, $buf, $len - length $buf, length $buf);
36 0 0         if (!defined $n) {
    0          
37             # warn "read error, ignoring it: $!";
38 0           sleep 1;
39             } elsif ($n == 0) {
40 0           die "unexpected EOF";
41             }
42             }
43 0           return $buf;
44             }
45              
46             sub send_packet {
47 0     0 0   my ($self, $data) = @_;
48 0           my $json = JSON::PP::encode_json($data);
49             # warn "sending $json\n";
50 0           utf8::encode($json);
51 0           my $bytes = pack("N", length $json) . $json;
52 0           while (length $bytes) {
53 0           my $n = syswrite($$self, $bytes);
54 0 0         if (!defined $n) {
55             # warn "write error, ignoring: $!";
56 0           sleep 1;
57             }
58 0           substr($bytes, 0, $n) = "";
59             }
60             }
61              
62             sub recv_fd {
63 0     0 0   my $self = shift;
64             # receive tap file descriptor through $parent_socket
65 0           my $msg_mdr = Socket::MsgHdr->new(buflen => 8192, controllen => 256);
66 0           recvmsg($$self, $msg_mdr);
67 0           my ($level, $type, $data) = $msg_mdr->cmsghdr();
68 0   0       unpack('i', $data) // die "Failed to receive tap file descriptor: $!";
69             }
70              
71             sub send_fd {
72 0     0 0   my ($self, $fd) = @_;
73 0           my $msg_hdr = Socket::MsgHdr->new(buflen => 512);
74 0           $msg_hdr->cmsghdr(SOL_SOCKET, # cmsg_level
75             SCM_RIGHTS, # cmsg_type
76             pack("i", fileno($fd))); # cmsg_data
77 0 0         sendmsg($$self, $msg_hdr)
78             or die "sendmsg failed: $!";
79             }
80              
81             1;