1 | package Mojo::IOLoop::Server;
|
---|
2 | use Mojo::Base 'Mojo::EventEmitter';
|
---|
3 |
|
---|
4 | use Carp 'croak';
|
---|
5 | use IO::Socket::IP;
|
---|
6 | use IO::Socket::UNIX;
|
---|
7 | use Mojo::IOLoop;
|
---|
8 | use Mojo::IOLoop::TLS;
|
---|
9 | use Scalar::Util 'weaken';
|
---|
10 | use Socket qw(IPPROTO_TCP TCP_NODELAY);
|
---|
11 |
|
---|
12 | has reactor => sub { Mojo::IOLoop->singleton->reactor };
|
---|
13 |
|
---|
14 | sub DESTROY {
|
---|
15 | my $self = shift;
|
---|
16 | $ENV{MOJO_REUSE} =~ s/(?:^|\,)\Q$self->{reuse}\E// if $self->{reuse};
|
---|
17 | $self->stop if $self->{handle} && $self->reactor;
|
---|
18 | }
|
---|
19 |
|
---|
20 | sub generate_port {
|
---|
21 | IO::Socket::IP->new(Listen => 5, LocalAddr => '127.0.0.1')->sockport;
|
---|
22 | }
|
---|
23 |
|
---|
24 | sub handle { shift->{handle} }
|
---|
25 |
|
---|
26 | sub is_accepting { !!shift->{active} }
|
---|
27 |
|
---|
28 | sub listen {
|
---|
29 | my ($self, $args) = (shift, ref $_[0] ? $_[0] : {@_});
|
---|
30 |
|
---|
31 | # Look for reusable file descriptor
|
---|
32 | my $path = $args->{path};
|
---|
33 | my $address = $args->{address} || '0.0.0.0';
|
---|
34 | my $port = $args->{port};
|
---|
35 | $ENV{MOJO_REUSE} ||= '';
|
---|
36 | my $fd
|
---|
37 | = ($path && $ENV{MOJO_REUSE} =~ /(?:^|\,)unix:\Q$path\E:(\d+)/)
|
---|
38 | || ($port && $ENV{MOJO_REUSE} =~ /(?:^|\,)\Q$address:$port\E:(\d+)/)
|
---|
39 | ? $1
|
---|
40 | : undef;
|
---|
41 |
|
---|
42 | # Allow file descriptor inheritance
|
---|
43 | local $^F = 1023;
|
---|
44 |
|
---|
45 | # Reuse file descriptor
|
---|
46 | my $handle;
|
---|
47 | my $class = $path ? 'IO::Socket::UNIX' : 'IO::Socket::IP';
|
---|
48 | if (defined($fd //= $args->{fd})) {
|
---|
49 | $handle = $class->new_from_fd($fd, 'r')
|
---|
50 | or croak "Can't open file descriptor $fd: $!";
|
---|
51 | }
|
---|
52 |
|
---|
53 | else {
|
---|
54 | my %options
|
---|
55 | = (Listen => $args->{backlog} // SOMAXCONN, Type => SOCK_STREAM);
|
---|
56 |
|
---|
57 | # UNIX domain socket
|
---|
58 | my $reuse;
|
---|
59 | if ($path) {
|
---|
60 | unlink $path if -S $path;
|
---|
61 | $options{Local} = $path;
|
---|
62 | $handle = $class->new(%options) or croak "Can't create listen socket: $!";
|
---|
63 | $reuse = $self->{reuse} = join ':', 'unix', $path, fileno $handle;
|
---|
64 | }
|
---|
65 |
|
---|
66 | # IP socket
|
---|
67 | else {
|
---|
68 | $options{LocalAddr} = $address;
|
---|
69 | $options{LocalAddr} =~ s/[\[\]]//g;
|
---|
70 | $options{LocalPort} = $port if $port;
|
---|
71 | $options{ReuseAddr} = 1;
|
---|
72 | $options{ReusePort} = $args->{reuse};
|
---|
73 | $handle = $class->new(%options) or croak "Can't create listen socket: $@";
|
---|
74 | $fd = fileno $handle;
|
---|
75 | $reuse = $self->{reuse} = join ':', $address, $handle->sockport, $fd;
|
---|
76 | }
|
---|
77 |
|
---|
78 | $ENV{MOJO_REUSE} .= length $ENV{MOJO_REUSE} ? ",$reuse" : "$reuse";
|
---|
79 | }
|
---|
80 | $handle->blocking(0);
|
---|
81 | @$self{qw(args handle)} = ($args, $handle);
|
---|
82 |
|
---|
83 | croak 'IO::Socket::SSL 2.009+ required for TLS support'
|
---|
84 | if !Mojo::IOLoop::TLS->can_tls && $args->{tls};
|
---|
85 | }
|
---|
86 |
|
---|
87 | sub port { shift->{handle}->sockport }
|
---|
88 |
|
---|
89 | sub start {
|
---|
90 | my $self = shift;
|
---|
91 | weaken $self;
|
---|
92 | ++$self->{active}
|
---|
93 | and $self->reactor->io($self->{handle} => sub { $self->_accept });
|
---|
94 | }
|
---|
95 |
|
---|
96 | sub stop { delete($_[0]{active}) and $_[0]->reactor->remove($_[0]{handle}) }
|
---|
97 |
|
---|
98 | sub _accept {
|
---|
99 | my $self = shift;
|
---|
100 |
|
---|
101 | # Greedy accept
|
---|
102 | my $args = $self->{args};
|
---|
103 | my $accepted = 0;
|
---|
104 | while ($self->{active} && !($args->{single_accept} && $accepted++)) {
|
---|
105 | return unless my $handle = $self->{handle}->accept;
|
---|
106 | $handle->blocking(0);
|
---|
107 |
|
---|
108 | # Disable Nagle's algorithm
|
---|
109 | setsockopt $handle, IPPROTO_TCP, TCP_NODELAY, 1;
|
---|
110 |
|
---|
111 | $self->emit(accept => $handle) and next unless $args->{tls};
|
---|
112 |
|
---|
113 | # Start TLS handshake
|
---|
114 | my $tls = Mojo::IOLoop::TLS->new($handle)->reactor($self->reactor);
|
---|
115 | $tls->on(upgrade => sub { $self->emit(accept => pop) });
|
---|
116 | $tls->on(error => sub { });
|
---|
117 | $tls->negotiate(%$args, server => 1);
|
---|
118 | }
|
---|
119 | }
|
---|
120 |
|
---|
121 | 1;
|
---|
122 |
|
---|
123 | =encoding utf8
|
---|
124 |
|
---|
125 | =head1 NAME
|
---|
126 |
|
---|
127 | Mojo::IOLoop::Server - Non-blocking TCP and UNIX domain socket server
|
---|
128 |
|
---|
129 | =head1 SYNOPSIS
|
---|
130 |
|
---|
131 | use Mojo::IOLoop::Server;
|
---|
132 |
|
---|
133 | # Create listen socket
|
---|
134 | my $server = Mojo::IOLoop::Server->new;
|
---|
135 | $server->on(accept => sub {
|
---|
136 | my ($server, $handle) = @_;
|
---|
137 | ...
|
---|
138 | });
|
---|
139 | $server->listen(port => 3000);
|
---|
140 |
|
---|
141 | # Start and stop accepting connections
|
---|
142 | $server->start;
|
---|
143 | $server->stop;
|
---|
144 |
|
---|
145 | # Start reactor if necessary
|
---|
146 | $server->reactor->start unless $server->reactor->is_running;
|
---|
147 |
|
---|
148 | =head1 DESCRIPTION
|
---|
149 |
|
---|
150 | L<Mojo::IOLoop::Server> accepts TCP/IP and UNIX domain socket connections for
|
---|
151 | L<Mojo::IOLoop>.
|
---|
152 |
|
---|
153 | =head1 EVENTS
|
---|
154 |
|
---|
155 | L<Mojo::IOLoop::Server> inherits all events from L<Mojo::EventEmitter> and can
|
---|
156 | emit the following new ones.
|
---|
157 |
|
---|
158 | =head2 accept
|
---|
159 |
|
---|
160 | $server->on(accept => sub {
|
---|
161 | my ($server, $handle) = @_;
|
---|
162 | ...
|
---|
163 | });
|
---|
164 |
|
---|
165 | Emitted for each accepted connection.
|
---|
166 |
|
---|
167 | =head1 ATTRIBUTES
|
---|
168 |
|
---|
169 | L<Mojo::IOLoop::Server> implements the following attributes.
|
---|
170 |
|
---|
171 | =head2 reactor
|
---|
172 |
|
---|
173 | my $reactor = $server->reactor;
|
---|
174 | $server = $server->reactor(Mojo::Reactor::Poll->new);
|
---|
175 |
|
---|
176 | Low-level event reactor, defaults to the C<reactor> attribute value of the
|
---|
177 | global L<Mojo::IOLoop> singleton.
|
---|
178 |
|
---|
179 | =head1 METHODS
|
---|
180 |
|
---|
181 | L<Mojo::IOLoop::Server> inherits all methods from L<Mojo::EventEmitter> and
|
---|
182 | implements the following new ones.
|
---|
183 |
|
---|
184 | =head2 generate_port
|
---|
185 |
|
---|
186 | my $port = Mojo::IOLoop::Server->generate_port;
|
---|
187 |
|
---|
188 | Find a free TCP port, primarily used for tests.
|
---|
189 |
|
---|
190 | =head2 handle
|
---|
191 |
|
---|
192 | my $handle = $server->handle;
|
---|
193 |
|
---|
194 | Get handle for server, usually an L<IO::Socket::IP> object.
|
---|
195 |
|
---|
196 | =head2 is_accepting
|
---|
197 |
|
---|
198 | my $bool = $server->is_accepting;
|
---|
199 |
|
---|
200 | Check if connections are currently being accepted.
|
---|
201 |
|
---|
202 | =head2 listen
|
---|
203 |
|
---|
204 | $server->listen(port => 3000);
|
---|
205 | $server->listen({port => 3000});
|
---|
206 |
|
---|
207 | Create a new listen socket. Note that TLS support depends on L<IO::Socket::SSL>
|
---|
208 | (2.009+).
|
---|
209 |
|
---|
210 | These options are currently available:
|
---|
211 |
|
---|
212 | =over 2
|
---|
213 |
|
---|
214 | =item address
|
---|
215 |
|
---|
216 | address => '127.0.0.1'
|
---|
217 |
|
---|
218 | Local address to listen on, defaults to C<0.0.0.0>.
|
---|
219 |
|
---|
220 | =item backlog
|
---|
221 |
|
---|
222 | backlog => 128
|
---|
223 |
|
---|
224 | Maximum backlog size, defaults to C<SOMAXCONN>.
|
---|
225 |
|
---|
226 | =item fd
|
---|
227 |
|
---|
228 | fd => 3
|
---|
229 |
|
---|
230 | File descriptor with an already prepared listen socket.
|
---|
231 |
|
---|
232 | =item path
|
---|
233 |
|
---|
234 | path => '/tmp/myapp.sock'
|
---|
235 |
|
---|
236 | Path for UNIX domain socket to listen on.
|
---|
237 |
|
---|
238 | =item port
|
---|
239 |
|
---|
240 | port => 80
|
---|
241 |
|
---|
242 | Port to listen on, defaults to a random port.
|
---|
243 |
|
---|
244 | =item reuse
|
---|
245 |
|
---|
246 | reuse => 1
|
---|
247 |
|
---|
248 | Allow multiple servers to use the same port with the C<SO_REUSEPORT> socket
|
---|
249 | option.
|
---|
250 |
|
---|
251 | =item single_accept
|
---|
252 |
|
---|
253 | single_accept => 1
|
---|
254 |
|
---|
255 | Only accept one connection at a time.
|
---|
256 |
|
---|
257 | =item tls
|
---|
258 |
|
---|
259 | tls => 1
|
---|
260 |
|
---|
261 | Enable TLS.
|
---|
262 |
|
---|
263 | =item tls_ca
|
---|
264 |
|
---|
265 | tls_ca => '/etc/tls/ca.crt'
|
---|
266 |
|
---|
267 | Path to TLS certificate authority file.
|
---|
268 |
|
---|
269 | =item tls_cert
|
---|
270 |
|
---|
271 | tls_cert => '/etc/tls/server.crt'
|
---|
272 | tls_cert => {'mojolicious.org' => '/etc/tls/mojo.crt'}
|
---|
273 |
|
---|
274 | Path to the TLS cert file, defaults to a built-in test certificate.
|
---|
275 |
|
---|
276 | =item tls_ciphers
|
---|
277 |
|
---|
278 | tls_ciphers => 'AES128-GCM-SHA256:RC4:HIGH:!MD5:!aNULL:!EDH'
|
---|
279 |
|
---|
280 | TLS cipher specification string. For more information about the format see
|
---|
281 | L<https://www.openssl.org/docs/manmaster/apps/ciphers.html#CIPHER-STRINGS>.
|
---|
282 |
|
---|
283 | =item tls_key
|
---|
284 |
|
---|
285 | tls_key => '/etc/tls/server.key'
|
---|
286 | tls_key => {'mojolicious.org' => '/etc/tls/mojo.key'}
|
---|
287 |
|
---|
288 | Path to the TLS key file, defaults to a built-in test key.
|
---|
289 |
|
---|
290 | =item tls_protocols
|
---|
291 |
|
---|
292 | tls_protocols => ['foo', 'bar']
|
---|
293 |
|
---|
294 | ALPN protocols to negotiate.
|
---|
295 |
|
---|
296 | =item tls_verify
|
---|
297 |
|
---|
298 | tls_verify => 0x00
|
---|
299 |
|
---|
300 | TLS verification mode.
|
---|
301 |
|
---|
302 | =item tls_version
|
---|
303 |
|
---|
304 | tls_version => 'TLSv1_2'
|
---|
305 |
|
---|
306 | TLS protocol version.
|
---|
307 |
|
---|
308 | =back
|
---|
309 |
|
---|
310 | =head2 port
|
---|
311 |
|
---|
312 | my $port = $server->port;
|
---|
313 |
|
---|
314 | Get port this server is listening on.
|
---|
315 |
|
---|
316 | =head2 start
|
---|
317 |
|
---|
318 | $server->start;
|
---|
319 |
|
---|
320 | Start or resume accepting connections.
|
---|
321 |
|
---|
322 | =head2 stop
|
---|
323 |
|
---|
324 | $server->stop;
|
---|
325 |
|
---|
326 | Stop accepting connections.
|
---|
327 |
|
---|
328 | =head1 SEE ALSO
|
---|
329 |
|
---|
330 | L<Mojolicious>, L<Mojolicious::Guides>, L<https://mojolicious.org>.
|
---|
331 |
|
---|
332 | =cut
|
---|