File Coverage

blib/lib/Mojo/IOLoop/Server.pm
Criterion Covered Total %
statement 72 82 87.8
branch 24 36 66.6
condition 20 26 76.9
subroutine 18 21 85.7
pod 7 7 100.0
total 141 172 81.9


line stmt bran cond sub pod time code
1             package Mojo::IOLoop::Server;
2 67     67   105823 use Mojo::Base 'Mojo::EventEmitter';
  67         159  
  67         499  
3              
4 67     67   684 use Carp qw(croak);
  67         146  
  67         4547  
5 67     67   3142 use IO::Socket::IP;
  67         110626  
  67         748  
6 67     67   46077 use IO::Socket::UNIX;
  67         172  
  67         818  
7 67     67   172951 use Mojo::File qw(path);
  67         165  
  67         4740  
8 67     67   3204 use Mojo::IOLoop;
  67         161  
  67         532  
9 67     67   919 use Mojo::IOLoop::TLS;
  67         159  
  67         489  
10 67     67   440 use Scalar::Util qw(weaken);
  67         170  
  67         4053  
11 67     67   407 use Socket qw(IPPROTO_TCP TCP_NODELAY);
  67         200  
  67         165124  
12              
13             has reactor => sub { Mojo::IOLoop->singleton->reactor }, weak => 1;
14              
15             sub DESTROY {
16 143     143   6144 my $self = shift;
17 143 100       7741 $ENV{MOJO_REUSE} =~ s/(?:^|\,)\Q$self->{reuse}\E// if $self->{reuse};
18 143 100 100     1238 $self->stop if $self->{handle} && $self->reactor;
19             }
20              
21 0     0 1 0 sub generate_port { IO::Socket::IP->new(Listen => 5, LocalAddr => '127.0.0.1')->sockport }
22              
23 1     1 1 5 sub handle { shift->{handle} }
24              
25 4     4 1 22 sub is_accepting { !!shift->{active} }
26              
27             sub listen {
28 179 100   179 1 706 my ($self, $args) = (shift, ref $_[0] ? $_[0] : {@_});
29              
30             # Look for reusable file descriptor
31 179         523 my $path = $args->{path};
32 179   50     746 my $address = $args->{address} || '0.0.0.0';
33 179         384 my $port = $args->{port};
34 179   100     1638 $ENV{MOJO_REUSE} ||= '';
35             my $fd = ($path && $ENV{MOJO_REUSE} =~ /(?:^|\,)unix:\Q$path\E:(\d+)/)
36 179 50 33     1528 || ($port && $ENV{MOJO_REUSE} =~ /(?:^|\,)\Q$address:$port\E:(\d+)/) ? $1 : undef;
37              
38             # Allow file descriptor inheritance
39 179         1096 local $^F = 1023;
40              
41             # Reuse file descriptor
42 179         366 my $handle;
43 179 50       662 my $class = $path ? 'IO::Socket::UNIX' : 'IO::Socket::IP';
44 179 100 66     1695 if (defined($fd //= $args->{fd})) {
45 1 50       15 $handle = $class->new_from_fd($fd, 'r') or croak "Can't open file descriptor $fd: $!";
46             }
47              
48             else {
49 178   50     1818 my %options = (Listen => $args->{backlog} // SOMAXCONN, Type => SOCK_STREAM);
50              
51             # UNIX domain socket
52 178         869 my $reuse;
53 178 50       441 if ($path) {
54 0 0       0 path($path)->remove if -S $path;
55 0         0 $options{Local} = $path;
56 0 0       0 $handle = $class->new(%options) or croak "Can't create listen socket: $!";
57 0         0 $reuse = $self->{reuse} = join ':', 'unix', $path, fileno $handle;
58             }
59              
60             # IP socket
61             else {
62 178         1202 $options{LocalAddr} = $address;
63 178         631 $options{LocalAddr} =~ y/[]//d;
64 178 50       534 $options{LocalPort} = $port if $port;
65 178         488 $options{ReuseAddr} = 1;
66 178         527 $options{ReusePort} = $args->{reuse};
67 178 50       2270 $handle = $class->new(%options) or croak "Can't create listen socket: $@";
68 178         182280 $fd = fileno $handle;
69 178         861 $reuse = $self->{reuse} = join ':', $address, $handle->sockport, $fd;
70             }
71              
72 178 100       13541 $ENV{MOJO_REUSE} .= length $ENV{MOJO_REUSE} ? ",$reuse" : "$reuse";
73             }
74 179         1237 $handle->blocking(0);
75 179         3604 @$self{qw(args handle)} = ($args, $handle);
76              
77 179 100 100     2458 croak 'IO::Socket::SSL 2.009+ required for TLS support' if !Mojo::IOLoop::TLS->can_tls && $args->{tls};
78             }
79              
80 178     178 1 1232 sub port { shift->{handle}->sockport }
81              
82             sub start {
83 427     427 1 967 my $self = shift;
84 427         915 weaken $self;
85 427 50   235   2316 ++$self->{active} and $self->reactor->io($self->{handle} => sub { $self->_accept })->watch($self->{handle}, 1, 0);
  235         1305  
86             }
87              
88 492 100   492 1 2422 sub stop { delete($_[0]{active}) and $_[0]->reactor->remove($_[0]{handle}) }
89              
90             sub _accept {
91 235     235   587 my $self = shift;
92              
93             # Greedy accept
94 235         670 my $args = $self->{args};
95 235         471 my $accepted = 0;
96 235   100     1830 while ($self->{active} && !($args->{single_accept} && $accepted++)) {
      100        
97 465 100       2687 return unless my $handle = $self->{handle}->accept;
98 235         48402 $handle->blocking(0);
99              
100             # Disable Nagle's algorithm
101 235         4768 setsockopt $handle, IPPROTO_TCP, TCP_NODELAY, 1;
102              
103 235 50 50     2294 $self->emit(accept => $handle) and next unless $args->{tls};
104              
105             # Start TLS handshake
106 0           my $tls = Mojo::IOLoop::TLS->new($handle)->reactor($self->reactor);
107 0     0     $tls->on(upgrade => sub { $self->emit(accept => pop) });
  0            
108 0     0     $tls->on(error => sub { });
109 0           $tls->negotiate(%$args, server => 1);
110             }
111             }
112              
113             1;
114              
115             =encoding utf8
116              
117             =head1 NAME
118              
119             Mojo::IOLoop::Server - Non-blocking TCP and UNIX domain socket server
120              
121             =head1 SYNOPSIS
122              
123             use Mojo::IOLoop::Server;
124              
125             # Create listen socket
126             my $server = Mojo::IOLoop::Server->new;
127             $server->on(accept => sub ($server, $handle) {...});
128             $server->listen(port => 3000);
129              
130             # Start and stop accepting connections
131             $server->start;
132             $server->stop;
133              
134             # Start reactor if necessary
135             $server->reactor->start unless $server->reactor->is_running;
136              
137             =head1 DESCRIPTION
138              
139             L accepts TCP/IP and UNIX domain socket connections for L.
140              
141             =head1 EVENTS
142              
143             L inherits all events from L and can emit the following new ones.
144              
145             =head2 accept
146              
147             $server->on(accept => sub ($server, $handle) {...});
148              
149             Emitted for each accepted connection.
150              
151             =head1 ATTRIBUTES
152              
153             L implements the following attributes.
154              
155             =head2 reactor
156              
157             my $reactor = $server->reactor;
158             $server = $server->reactor(Mojo::Reactor::Poll->new);
159              
160             Low-level event reactor, defaults to the C attribute value of the global L singleton. Note that
161             this attribute is weakened.
162              
163             =head1 METHODS
164              
165             L inherits all methods from L and implements the following new ones.
166              
167             =head2 generate_port
168              
169             my $port = Mojo::IOLoop::Server->generate_port;
170              
171             Find a free TCP port, primarily used for tests.
172              
173             =head2 handle
174              
175             my $handle = $server->handle;
176              
177             Get handle for server, usually an L object.
178              
179             =head2 is_accepting
180              
181             my $bool = $server->is_accepting;
182              
183             Check if connections are currently being accepted.
184              
185             =head2 listen
186              
187             $server->listen(port => 3000);
188             $server->listen({port => 3000});
189              
190             Create a new listen socket. Note that TLS support depends on L (2.009+).
191              
192             These options are currently available:
193              
194             =over 2
195              
196             =item address
197              
198             address => '127.0.0.1'
199              
200             Local address to listen on, defaults to C<0.0.0.0>.
201              
202             =item backlog
203              
204             backlog => 128
205              
206             Maximum backlog size, defaults to C.
207              
208             =item fd
209              
210             fd => 3
211              
212             File descriptor with an already prepared listen socket.
213              
214             =item path
215              
216             path => '/tmp/myapp.sock'
217              
218             Path for UNIX domain socket to listen on.
219              
220             =item port
221              
222             port => 80
223              
224             Port to listen on, defaults to a random port.
225              
226             =item reuse
227              
228             reuse => 1
229              
230             Allow multiple servers to use the same port with the C socket option.
231              
232             =item single_accept
233              
234             single_accept => 1
235              
236             Only accept one connection at a time.
237              
238             =item tls
239              
240             tls => 1
241              
242             Enable TLS.
243              
244             =item tls_ca
245              
246             tls_ca => '/etc/tls/ca.crt'
247              
248             Path to TLS certificate authority file.
249              
250             =item tls_cert
251              
252             tls_cert => '/etc/tls/server.crt'
253             tls_cert => {'mojolicious.org' => '/etc/tls/mojo.crt'}
254              
255             Path to the TLS cert file, defaults to a built-in test certificate.
256              
257             =item tls_key
258              
259             tls_key => '/etc/tls/server.key'
260             tls_key => {'mojolicious.org' => '/etc/tls/mojo.key'}
261              
262             Path to the TLS key file, defaults to a built-in test key.
263              
264             =item tls_options
265              
266             tls_options => {SSL_alpn_protocols => ['foo', 'bar'], SSL_verify_mode => 0x00}
267              
268             Additional options for L.
269              
270             =back
271              
272             =head2 port
273              
274             my $port = $server->port;
275              
276             Get port this server is listening on.
277              
278             =head2 start
279              
280             $server->start;
281              
282             Start or resume accepting connections.
283              
284             =head2 stop
285              
286             $server->stop;
287              
288             Stop accepting connections.
289              
290             =head1 SEE ALSO
291              
292             L, L, L.
293              
294             =cut