File Coverage

blib/lib/Lock/Socket.pm
Criterion Covered Total %
statement 172 197 87.3
branch 46 64 71.8
condition 11 20 55.0
subroutine 33 33 100.0
pod 1 6 16.6
total 263 320 82.1


line stmt bran cond sub pod time code
1             package Lock::Socket::Mo;
2              
3             #<<< Do not perltidy this
4             BEGIN {
5             # use Mo qw'builder default import is required';
6             # The following line of code was produced from the previous line by
7             # Mo::Inline version 0.39
8 2 50 50 2   1239 no warnings;my$M=__PACKAGE__.'::';*{$M.Object::new}=sub{my$c=shift;my$s=bless{@_},$c;my%n=%{$c.::.':E'};map{$s->{$_}=$n{$_}->()if!exists$s->{$_}}keys%n;$s};*{$M.import}=sub{import warnings;$^H|=1538;my($P,%e,%o)=caller.'::';shift;eval"no Mo::$_",&{$M.$_.::e}($P,\%e,\%o,\@_)for@_;return if$e{M};%e=(extends,sub{eval"no $_[0]()";@{$P.ISA}=$_[0]},has,sub{my$n=shift;my$m=sub{$#_?$_[0]{$n}=$_[1]:$_[0]{$n}};@_=(default,@_)if!($#_%2);$m=$o{$_}->($m,$n,@_)for sort keys%o;*{$P.$n}=$m},%e,);*{$P.$_}=$e{$_}for keys%e;@{$P.ISA}=$M.Object};*{$M.'builder::e'}=sub{my($P,$e,$o)=@_;$o->{builder}=sub{my($m,$n,%a)=@_;my$b=$a{builder}or return$m;my$i=exists$a{lazy}?$a{lazy}:!${$P.':N'};$i or ${$P.':E'}{$n}=\&{$P.$b}and return$m;sub{$#_?$m->(@_):!exists$_[0]{$n}?$_[0]{$n}=$_[0]->$b:$m->(@_)}}};*{$M.'default::e'}=sub{my($P,$e,$o)=@_;$o->{default}=sub{my($m,$n,%a)=@_;exists$a{default}or return$m;my($d,$r)=$a{default};my$g='HASH'eq($r=ref$d)?sub{+{%$d}}:'ARRAY'eq$r?sub{[@$d]}:'CODE'eq$r?$d:sub{$d};my$i=exists$a{lazy}?$a{lazy}:!${$P.':N'};$i or ${$P.':E'}{$n}=$g and return$m;sub{$#_?$m->(@_):!exists$_[0]{$n}?$_[0]{$n}=$g->(@_):$m->(@_)}}};my$i=\&import;*{$M.import}=sub{(@_==2 and not$_[1])?pop@_:@_==1?push@_,grep!/import/,@f:();goto&$i};*{$M.'is::e'}=sub{my($P,$e,$o)=@_;$o->{is}=sub{my($m,$n,%a)=@_;$a{is}or return$m;sub{$#_&&$a{is}eq'ro'&&caller ne'Mo::coerce'?die$n.' is ro':$m->(@_)}}};*{$M.'required::e'}=sub{my($P,$e,$o)=@_;$o->{required}=sub{my($m,$n,%a)=@_;if($a{required}){my$C=*{$P."new"}{CODE}||*{$M.Object::new}{CODE};no warnings 'redefine';*{$P."new"}=sub{my$s=$C->(@_);my%a=@_[1..$#_];if(!exists$a{$n}){require Carp;Carp::croak($n." required")}$s}}$m}};@f=qw[builder default import is required];use strict;use warnings;
  2 50 50 2   4  
  2 100 33 2   3196  
  2 50 33 2   13  
  2 100 50 2   3  
  2 50   2   372  
  2 50   2   10  
  2 0   2   7  
  2 0   2   72  
  2 100   2   11  
  2 50   2   3  
  2 50   2   76  
  2 50   2   6  
  2 100   79   15  
  2 100       21  
  27 100       39  
  27 50       101  
  27 50       30  
  27 50       142  
  27 50       47  
  34 50       149  
  27 100       65  
  2 100       24  
  2         7  
  4         31  
  4         5  
  4         17  
  4         5  
  4         291  
  16         72  
  4         16  
  4         35  
  0         0  
  0         0  
  0         0  
  12         18  
  12         34  
  114         611  
  12         35  
  12         69  
  12         18  
  12         53  
  4         14  
  8         47  
  4         11  
  4         257  
  2         8  
  2         14  
  4         9  
  4         233  
  12         40  
  12         73  
  2         7  
  0         0  
  2         7  
  2         24  
  2         11  
  0         0  
  0         0  
  2         9  
  2         27  
  4         8  
  4         228  
  12         31  
  12         43  
  6         12  
  6         29  
  0         0  
  0         0  
  0         0  
  6         13  
  4         56  
  6         14  
  2         15  
  4         25  
  42         167  
  2         5  
  2         6  
  2         8  
  4         61  
  4         16  
  2         6  
  2         28  
  4         10  
  4         226  
  12         37  
  12         27  
  12         78  
  142         955  
  2         6  
  2         27  
  4         9  
  4         38  
  12         28  
  12         26  
  4         6  
  4         15  
  4         30  
  27         1956  
  27         86  
  27         66  
  1         9  
  1         275  
  26         125  
  12         37  
  2         6  
  2         957  
  0         0  
  0         0  
  2         779  
  0         0  
  0         0  
  2         793  
  0         0  
  0         0  
  2         730  
  0         0  
  0         0  
  2         900  
  0         0  
  0         0  
  2         1161  
  0         0  
  0         0  
  2         788  
  0         0  
  0         0  
  2         907  
  0         0  
  0         0  
9 2         57 $INC{'Lock/Socket/Mo.pm'} = __FILE__;
10             }
11             1;
12             #>>>
13              
14             package Lock::Socket::Error;
15 2     2   42 use Lock::Socket::Mo;
  2         3  
  2         14  
16 2     2   5942 use overload '""' => sub { $_[0]->msg }, fallback => 1;
  2     8   8686  
  2         23  
  8         1666  
17              
18             has msg => (
19             is => 'ro',
20             required => 1,
21             );
22              
23             1;
24              
25             package Lock::Socket;
26 2     2   183 use strict;
  2         4  
  2         288  
27 2     2   10 use warnings;
  2         3  
  2         108  
28 2     2   10 use Carp ();
  2         4  
  2         31  
29 2     2   10 use Lock::Socket::Mo;
  2         4  
  2         11  
30 2     2   2489 use Socket;
  2         8741  
  2         1312  
31              
32             our @VERSION = '0.0.4';
33             our @CARP_NOT;
34              
35             @Lock::Socket::Error::Bind::ISA = ('Lock::Socket::Error');
36             @Lock::Socket::Error::Socket::ISA = ('Lock::Socket::Error');
37             @Lock::Socket::Error::Usage::ISA = ('Lock::Socket::Error');
38             @Lock::Socket::Error::Import::ISA = ('Lock::Socket::Error');
39              
40             ### Function Interface ###
41              
42             sub import {
43 3     3   372 my $class = shift;
44 3         6 my $caller = caller;
45 2     2   15 no strict 'refs';
  2         3  
  2         1461  
46              
47 3         29 foreach my $token (@_) {
48 3 100       12 if ( $token eq 'lock_socket' ) {
    100          
49 1         5 *{ $caller . '::lock_socket' } = sub {
50 6   66 6   919 my $port = shift
51             || __PACKAGE__->err( 'Usage', 'usage: lock_socket($PORT)' );
52 5         7 my $addr = shift;
53 5 100       25 my $sock = Lock::Socket->new(
54             port => $port,
55             defined $addr ? ( addr => $addr ) : (),
56             );
57 5         13 $sock->lock;
58 3         9 return $sock;
59 1         4 };
60             }
61             elsif ( $token eq 'try_lock_socket' ) {
62 1         28 *{ $caller . '::try_lock_socket' } = sub {
63 4   66 4   868 my $port = shift
64             || __PACKAGE__->err( 'Usage',
65             'usage: try_lock_socket($PORT)' );
66 3         5 my $addr = shift;
67 3 100       17 my $sock = Lock::Socket->new(
68             port => $port,
69             defined $addr ? ( addr => $addr ) : (),
70             );
71 3         9 $sock->try_lock;
72 3 100       8 return $sock if $sock->_is_locked;
73 1         16 return undef;
74             }
75 1         5 }
76             else {
77 1         6 __PACKAGE__->err( 'Import',
78             'not exported by Lock::Socket: ' . $token );
79             }
80             }
81             }
82              
83             ### Object Attributes ###
84              
85             has port => (
86             is => 'ro',
87             required => 1,
88             );
89              
90             has addr => (
91             is => 'ro',
92             default => sub {
93             return join( '.', 127, unpack( 'C2', pack( "n", $< ) ), 1 )
94             unless $^O =~ m/bsd$/;
95             return '127.0.0.1';
96             },
97             );
98              
99             has _inet_addr => (
100             is => 'ro',
101             default => sub {
102             my $self = shift;
103             return inet_aton( $self->addr );
104             },
105             );
106              
107             has _fh => (
108             is => 'rw',
109             lazy => 0,
110             builder => '_fh_builder',
111             );
112              
113             sub _fh_builder {
114 19     19   27 my $self = shift;
115 19 50       3412 socket( my $fh, PF_INET, SOCK_STREAM, getprotobyname('tcp') )
116             || $self->err( 'Socket', "socket: $!" );
117 19         109 return $fh;
118             }
119              
120             sub fh {
121 18     18 0 32 $_[0]->_fh;
122             }
123              
124             has _is_locked => (
125             is => 'rw',
126             lazy => 0,
127             default => sub { 0 },
128             );
129              
130             sub is_locked {
131 6     6 0 922 $_[0]->_is_locked;
132             }
133              
134             ### Object Methods ###
135              
136             sub err {
137 9     9 0 16 my $self = shift;
138 9         16 my $class = 'Lock::Socket::Error::' . $_[0];
139 9         30 local @CARP_NOT = __PACKAGE__;
140 9         1215 die $class->new( msg => Carp::shortmess( $_[1] ) );
141             }
142              
143             sub lock {
144 20     20 1 30 my $self = shift;
145 20 100       38 return 1 if $self->_is_locked;
146              
147 18 100       40 bind( $self->fh, pack_sockaddr_in( $self->port, $self->_inet_addr ) )
148             || $self->err( 'Bind',
149             sprintf( 'bind: %s (%s:%d)', $!, $self->addr, $self->port ) );
150              
151 12         42 $self->_is_locked(1);
152             }
153              
154             sub try_lock {
155 6     6 0 24 my $self = shift;
156 6   100     10 return eval { $self->lock } || 0;
157             }
158              
159             sub unlock {
160 3     3 0 7 my $self = shift;
161 3 100       12 return 1 unless $self->_is_locked;
162              
163 2         6 close( $self->_fh );
164 2         9 $self->_fh( $self->_fh_builder );
165 2         10 $self->_is_locked(0);
166              
167 2         8 return 1;
168             }
169              
170             1;
171              
172             __END__