File Coverage

blib/lib/JIP/LockSocket.pm
Criterion Covered Total %
statement 46 46 100.0
branch 17 18 94.4
condition 5 6 83.3
subroutine 14 14 100.0
pod 0 4 0.0
total 82 88 93.1


line stmt bran cond sub pod time code
1             package JIP::LockSocket;
2              
3 1     1   2563 use 5.006;
  1         4  
4 1     1   4 use strict;
  1         1  
  1         16  
5 1     1   3 use warnings;
  1         1  
  1         31  
6 1     1   352 use JIP::ClassField 0.05;
  1         2298  
  1         3  
7 1     1   46 use Carp qw(croak);
  1         2  
  1         33  
8 1     1   4 use English qw(-no_match_vars);
  1         1  
  1         4  
9 1     1   654 use Socket qw(inet_aton pack_sockaddr_in PF_INET SOCK_STREAM);
  1         3078  
  1         684  
10              
11             our $VERSION = '0.021';
12              
13             has [qw(port addr socket is_locked)] => (get => q{+}, set => q{-});
14              
15             sub new {
16 16     16 0 26763 my ($class, %param) = @ARG;
17              
18             # Mandatory options
19             croak q{Mandatory argument "port" is missing}
20 16 100       405 unless exists $param{'port'};
21              
22             # Check "port"
23 15         23 my $port = $param{'port'};
24 15 100 100     293 croak q{Bad argument "port"}
25             unless defined $port and $port =~ m{^\d+$}x;
26              
27             # Check "addr"
28             my $addr = (exists $param{'addr'} and length $param{'addr'})
29 13 100 66     36 ? $param{'addr'} : '127.0.0.1';
30              
31             # Class to object
32 13         42 return bless({}, $class)
33             ->_set_is_locked(0)
34             ->_set_port($port)
35             ->_set_addr($addr)
36             ->_set_socket(undef);
37             }
38              
39             # Lock or raise an exception
40             sub lock {
41 7     7 0 1699 my $self = shift;
42              
43             # Re-locking changes nothing
44 7 100       16 return $self if $self->is_locked;
45              
46 6         25 my $socket = $self->_init_socket;
47              
48 6 100       18 bind($socket, pack_sockaddr_in($self->port, $self->_get_inet_addr))
49             or croak(sprintf q{Can't lock port "%s": %s}, $self->port, $OS_ERROR);
50              
51 5         460 return $self->_set_socket($socket)->_set_is_locked(1);
52             }
53              
54             # Or just return undef
55             sub try_lock {
56 3     3 0 64 my $self = shift;
57              
58             # Re-locking changes nothing
59 3 100       5 return $self if $self->is_locked;
60              
61 2         13 my $socket = $self->_init_socket;
62              
63 2 100       8 if (bind($socket, pack_sockaddr_in($self->port, $self->_get_inet_addr))) {
64 1         17 return $self->_set_socket($socket)->_set_is_locked(1);
65             }
66             else {
67 1         29 return;
68             }
69             }
70              
71             # You can manually unlock
72             sub unlock {
73 15     15 0 41 my $self = shift;
74              
75             # Re-unlocking changes nothing
76 15 100       25 return $self if not $self->is_locked;
77              
78 6         36 return $self->_set_socket(undef)->_set_is_locked(0);
79             }
80              
81             # unlocking on scope exit
82             sub DESTROY {
83 13     13   4612 my $self = shift;
84 13         24 return $self->unlock;
85             }
86              
87             sub _get_inet_addr {
88 8     8   38 my $self = shift;
89 8         13 return inet_aton($self->addr);
90             }
91              
92             sub _init_socket {
93 8 50   8   922 socket(my $socket, PF_INET, SOCK_STREAM, getprotobyname('tcp'))
94             or croak(sprintf q{Can't init socket: %s}, $OS_ERROR);
95              
96 8         29 return $socket;
97             }
98              
99             1;
100              
101             __END__