File Coverage

blib/lib/Net/Server.pm
Criterion Covered Total %
statement 426 727 58.6
branch 203 458 44.3
condition 78 215 36.2
subroutine 70 105 66.6
pod 41 74 55.4
total 818 1579 51.8


line stmt bran cond sub pod time code
1             # -*- perl -*-
2             #
3             # Net::Server
4             # ABSTRACT: Extensible Perl internet server
5             #
6             # Copyright (C) 2001-2026
7             #
8             # Paul Seamons
9             #
10             # Rob Brown
11             #
12             # This package may be distributed under the terms of either the
13             # GNU General Public License
14             # or the
15             # Perl Artistic License
16             #
17             # All rights reserved.
18             #
19             ################################################################
20              
21             package Net::Server;
22              
23 54     54   618271 use strict;
  54         133  
  54         2948  
24 54     54   442 use Carp qw(croak);
  54         148  
  54         5501  
25 54     54   483 use Socket ();
  54         137  
  54         1745  
26 54     54   326 use IO::Socket ();
  54         136  
  54         1287  
27 54     54   1694 use IO::Select ();
  54         5106  
  54         1196  
28 54     54   24497 use POSIX ();
  54         383453  
  54         3611  
29 54         817 use Net::Server::Proto qw[
30             AF_INET
31             AF_INET6
32             AF_UNIX
33             SOCK_DGRAM
34             SOCK_STREAM
35             SOL_SOCKET
36             SO_TYPE
37             sockaddr_family
38             sockaddr_in
39             sockaddr_in6
40             inet_ntoa
41             inet_ntop
42             get_addr_info
43             ipv6_package
44             object
45             parse_info
46             safe_name_info
47 54     54   1782 ];
  54         136  
48 54         822795 use Net::Server::Daemonize qw(check_pid_file create_pid_file safe_fork
49 54     54   39574 get_uid get_gid set_uid set_gid);
  54         187  
50              
51             our $VERSION = '2.018';
52              
53             sub new {
54 97   33 97 1 3353 my $class = shift || croak "Missing class";
55 97 100       1876 my $args = @_ == 1 ? shift : {@_};
56 97         2293 return bless {server => {%$args}}, $class;
57             }
58              
59 88     88 0 211 sub net_server_type { __PACKAGE__ }
60 0     0 0 0 sub get_property { $_[0]->{'server'}->{$_[1]} }
61 0     0 0 0 sub set_property { $_[0]->{'server'}->{$_[1]} = $_[2] }
62              
63             sub run {
64 96 100   96 1 94745 my $self = ref($_[0]) ? shift() : shift->new; # pass package or object
65 96 100       5633 $self->{'server'}->{'_run_args'} = [@_ == 1 ? %{$_[0]} : @_];
  3         14  
66 96         2509 $self->_initialize; # configure all parameters
67              
68 96         1176 $self->post_configure; # verification of passed parameters
69 96         975 $self->post_configure_hook; # user customizable hook
70              
71 96         579 $self->pre_bind; # finalize ports to be bound
72 96         1100 $self->bind; # connect to port(s), setup selection handle for multi port
73 96         4758 $self->post_bind_hook; # user customizable hook
74 96         659 $self->post_bind; # allow for chrooting, becoming a different user and group
75              
76 96         869 $self->pre_loop_hook; # user customizable hook
77 96         531 $self->loop; # repeat accept/process cycle
78              
79 72         312 $self->server_close; # close the server and release the port
80             }
81              
82             sub run_client_connection {
83 32     32 1 100 my $self = shift;
84 32         99 my $c = $self->{'server'}->{'client'};
85              
86 32         536 $self->post_accept($c); # prepare client for processing
87 32         685 $self->get_client_info($c); # determines information about peer and local
88 32         398 $self->post_accept_hook($c); # user customizable hook
89              
90 32   33     235 my $ok = $self->allow_deny($c) && $self->allow_deny_hook($c); # do allow/deny check on client info
91 32 50       179 if ($ok) {
92 32         302 $self->process_request($c); # This is where the core functionality of a Net::Server should be.
93             } else {
94 0         0 $self->request_denied_hook($c); # user customizable hook
95             }
96              
97 12         439 $self->post_process_request_hook($ok); # user customizable hook
98 12         129 $self->post_process_request; # clean up client connection, etc
99 12         922 $self->post_client_connection_hook; # one last hook
100             }
101              
102             ###----------------------------------------------------------------###
103              
104             sub _initialize {
105 99     99   2248 my $self = shift;
106 99   50     2234 my $prop = $self->{'server'} ||= {};
107              
108 99 100       602 $self->commandline($self->_get_commandline) if ! eval { local $SIG{__DIE__}; $self->commandline }; # save for a HUP
  99         3080  
  99         1561  
109 99         776 $self->configure_hook; # user customizable hook
110 99         901 $self->configure; # allow for reading of commandline, program, and configuration file parameters
111              
112 99 50       168 my @defaults = %{ $self->default_values || {} }; # allow yet another way to pass defaults
  99         431  
113 99 100       435 $self->process_args(\@defaults) if @defaults;
114             }
115              
116             sub commandline {
117 195     195 0 576 my $self = shift;
118 195 50       2143 $self->{'server'}->{'commandline'} = ref($_[0]) ? shift : \@_ if @_;
    100          
119 195   66     84075 return $self->{'server'}->{'commandline'} || croak "commandline was not set during initialization";
120             }
121              
122             sub _get_commandline {
123 96     96   613 my $self = shift;
124 96         556 my $script = $0;
125 96 50 33     2456 $script = $ENV{'PWD'} .'/'. $script if $script =~ m|^[^/]+/| && $ENV{'PWD'}; # add absolute to relative - avoid Cwd
126 96         685 $script =~ /^(.+)$/; # untaint for later use in hup
127 96         993 return [$1, @ARGV]
128             }
129              
130       99 1   sub configure_hook {}
131              
132             sub configure {
133 127     127 1 321 my $self = shift;
134 127         570 my $prop = $self->{'server'};
135 127 100 66     2382 my $template = ($_[0] && ref($_[0])) ? shift : undef;
136              
137 127 100       592 $self->process_args(\@ARGV, $template) if @ARGV; # command line
138 127 50       1827 $self->process_args($prop->{'_run_args'}, $template) if $prop->{'_run_args'}; # passed to run
139              
140 127 100       380 if ($prop->{'conf_file'}) {
141 8         29 $self->process_args($self->_read_conf($prop->{'conf_file'}), $template);
142             } else {
143 119   50     714 my $def = $self->default_values || {};
144 119 100       657 $self->process_args($self->_read_conf($def->{'conf_file'}), $template) if $def->{'conf_file'};
145             }
146             }
147              
148 186     186 1 631 sub default_values { {} }
149              
150             sub post_configure {
151 96     96 1 478 my $self = shift;
152 96         308 my $prop = $self->{'server'};
153              
154 96 50 33     394 $prop->{'log_level'} = 2 if ! defined($prop->{'log_level'}) || $prop->{'log_level'} !~ /^\d+$/;
155 96 50       333 $prop->{'log_level'} = 4 if $prop->{'log_level'} > 4;
156 96         707 $self->initialize_logging;
157              
158 96 50       299 if ($prop->{'pid_file'}) { # see if a daemon is already running
159 0 0       0 if (! eval{ check_pid_file($prop->{'pid_file'}) }) {
  0         0  
160 0 0       0 warn $@ if !$ENV{'BOUND_SOCKETS'};
161 0         0 $self->fatal(my $e = $@);
162             }
163             }
164              
165 96 100       441 if (! $prop->{'_is_inet'}) { # completetely daemonize by closing STDIN, STDOUT (should be done before fork)
166 95 50 33     733 if ($prop->{'setsid'} || length($prop->{'log_file'})) {
167 0 0       0 open(STDIN, '<', '/dev/null') || die "Cannot read /dev/null [$!]";
168 0 0       0 open(STDOUT, '>', '/dev/null') || die "Cannot write /dev/null [$!]";
169             }
170             }
171              
172 96 50       311 if (!$ENV{'BOUND_SOCKETS'}) { # don't need to redo this if hup'ing
173 96 50 33     785 if ($prop->{'setsid'} || $prop->{'background'}) {
174 0         0 my $pid = eval { safe_fork() };
  0         0  
175 0 0       0 $self->fatal(my $e = $@) if ! defined $pid;
176 0 0       0 exit(0) if $pid;
177 0         0 $self->log(2, "Process Backgrounded");
178             }
179              
180 96 50       306 POSIX::setsid() if $prop->{'setsid'}; # completely remove myself from parent process
181             }
182              
183 96 50 33     524 if (length($prop->{'log_file'})
    50          
184             && !$prop->{'log_function'}) {
185 0         0 open STDERR, '>&_SERVER_LOG' || die "Cannot open STDERR to _SERVER_LOG [$!]";
186             } elsif ($prop->{'setsid'}) { # completely daemonize by closing STDERR (should be done after fork)
187 0         0 open STDERR, '>&STDOUT' || die "Cannot open STDERR to STDOUT [$!]";
188             }
189              
190             # allow for a pid file (must be done after backgrounding and chrooting)
191             # Remove of this pid may fail after a chroot to another location... however it doesn't interfere either.
192 96 50       339 if ($prop->{'pid_file'}) {
193 0 0       0 if (eval { create_pid_file($prop->{'pid_file'}) }) {
  0         0  
194 0         0 $prop->{'pid_file_unlink'} = 1;
195             } else {
196 0         0 $self->fatal(my $e = $@);
197             }
198             }
199              
200             # make sure that allow and deny look like array refs
201 96         360 $prop->{$_} = [] for grep {! ref $prop->{$_}} qw(allow deny cidr_allow cidr_deny);
  384         2250  
202              
203 96 50 0     339 $prop->{'reverse_lookups'} ||= 1 if $prop->{'double_reverse_lookups'};
204             $prop->{'double_reverse_lookups'} = $1 || $prop->{'double_reverse_lookups'} || 1
205 96 50 0     623 if $prop->{'reverse_lookups'} && $prop->{'reverse_lookups'} =~ /^(?:double|2)(.*)$/i;
      33        
206             }
207              
208             sub initialize_logging {
209 96     96 0 181 my $self = shift;
210 96         235 my $prop = $self->{'server'};
211 96 50       379 if (! defined($prop->{'log_file'})) {
212 96         312 $prop->{'log_file'} = ''; # log to STDERR
213 96         216 return;
214             }
215              
216             # pluggable logging
217 0 0       0 if (my $code = $prop->{'log_function'}) {
    0          
218 0 0       0 if (ref $code ne 'CODE') {
219 0         0 require Scalar::Util;
220 0 0       0 croak "Passed log_function $code was not a valid method of server, or was not a code object" if ! $self->can($code);
221 0         0 my $copy = $self;
222 0     0   0 $prop->{'log_function'} = sub { $copy->$code(@_) };
  0         0  
223 0         0 Scalar::Util::weaken($copy);
224             }
225             } elsif ($prop->{'log_file'} =~ /^([a-zA-Z]\w*(?:::[a-zA-Z]\w*)*)$/) {
226 0         0 my $pkg = "Net::Server::Log::$prop->{'log_file'}";
227 0         0 (my $file = "$pkg.pm") =~ s|::|/|g;
228 0 0 0     0 if (eval { require $file }) {
  0 0       0  
229 0         0 $prop->{'log_function'} = $pkg->initialize($self);
230 0         0 $prop->{'log_class'} = $pkg;
231 0         0 return;
232 0         0 } elsif ($file =~ /::/ || grep {-e "$_/$file"} @INC) {
233 0         0 $self->fatal("Unable to load log module $pkg from file $file: $@");
234             }
235             }
236              
237             # regular file based logging
238 0 0       0 croak "Unsecure filename \"$prop->{'log_file'}\"" if $prop->{'log_file'} !~ m|^([\:\w\.\-/\\]+)$|;
239 0         0 $prop->{'log_file'} = $1; # open a logging file
240 0 0       0 open(_SERVER_LOG, ">>", $prop->{'log_file'})
241             || croak "Couldn't open log file \"$prop->{'log_file'}\" [$!]";
242 0         0 _SERVER_LOG->autoflush(1);
243 0         0 push @{ $prop->{'chown_files'} }, $prop->{'log_file'};
  0         0  
244             }
245              
246       96 1   sub post_configure_hook {}
247              
248 95     95   285 sub _server_type { ref($_[0]) }
249              
250             sub pre_bind { # make sure we have good port parameters
251 95     95 1 249 my $self = shift;
252 95         179 my $prop = $self->{'server'};
253              
254 95         463 my $super = $self->net_server_type;
255 95         515 my $type = $self->_server_type;
256 95 100       1039 if ($self->isa('Net::Server::MultiType')) {
257 3   33     68 my $base = delete($prop->{'_recursive_multitype'}) || Net::Server::MultiType->net_server_type;
258 3         11 $super = "$super -> MultiType -> $base";
259             }
260 95 50       461 $type .= " (type $super)" if $type ne $super;
261 95         573 $self->log(2, $self->log_time ." $type starting! pid($$)");
262              
263 95         352 $prop->{'sock'} = [grep {$_} map { $self->proto_object($_) } @{ $self->prepared_ports }];
  136         713  
  136         722  
  95         576  
264 95 50       193 $self->fatal("No valid socket parameters found") if ! @{ $prop->{'sock'} };
  95         431  
265             }
266              
267             sub prepared_ports {
268 95     95 0 180 my $self = shift;
269 95         213 my $prop = $self->{'server'};
270              
271 95         405 my ($ports, $hosts, $protos, $ipvs) = @$prop{qw(port host proto ipv)};
272 95   33     339 $ports ||= $prop->{'ports'};
273 95 100 66     900 if (!defined($ports) || (ref($ports) && !@$ports)) {
      66        
274 7         30 $ports = $self->default_port;
275 7 50 33     37 if (!defined($ports) || (ref($ports) && !@$ports)) {
      33        
276 0         0 $ports = default_port();
277 0         0 $self->log(2, "Port Not Defined. Defaulting to '$ports'");
278             }
279             }
280              
281 95         189 my %bound;
282 95         408 my $bind = $prop->{'_bind'} = [];
283 95 100       570 for my $_port (ref($ports) ? @$ports : $ports) {
284 130 100       782 my $_host = ref($hosts) ? $hosts->[ @$bind >= @$hosts ? -1 : $#$bind + 1] : $hosts; # if ports are greater than hosts - augment with the last host
    50          
285 130 100       1290 my $_proto = ref($protos) ? $protos->[@$bind >= @$protos ? -1 : $#$bind + 1] : $protos;
    50          
286 130 100       559 my $_ipv = ref($ipvs) ? $ipvs->[ @$bind >= @$ipvs ? -1 : $#$bind + 1] : $ipvs;
    50          
287 130         587 foreach my $info ($self->port_info($_port, $_host, $_proto, $_ipv)) {
288 136         598 my ($port, $host, $proto, $ipv) = @$info{qw(port host proto ipv)}; # use cleaned values
289 136 50 33     1465 if ($port ne "0" && $bound{"$host\e$port\e$proto\e$ipv"}++) {
290 0         0 $self->log(2, "Duplicate configuration (\U$proto\E) on [$host]:$port with IPv$ipv) - skipping");
291 0         0 next;
292             }
293 136         508 push @$bind, $info;
294             }
295             }
296              
297 95         412 return $bind;
298             }
299              
300             sub port_info {
301 130     130 0 404 my ($self, $port, $host, $proto, $ipv) = @_;
302 130         1917 return parse_info($port, $host, $proto, $ipv, $self);
303             }
304              
305             sub proto_object {
306 136     136 0 529 my ($self, $info) = @_;
307 136         1006 return object($info, $self);
308             }
309              
310             sub bind { # bind to the port (This should serve all but INET)
311 25     25 1 65 my $self = shift;
312 25         87 my $prop = $self->{'server'};
313              
314 25 50       239 if (exists $ENV{'BOUND_SOCKETS'}) {
315 0         0 $self->restart_open_hook;
316 0         0 $self->log(2, "Binding open file descriptors");
317 0         0 my %map;
318 0         0 foreach my $info (split /\s*;\s*/, $ENV{'BOUND_SOCKETS'}) {
319 0         0 my ($fd, $host, $port, $proto, $ipv, $orig) = split /\|/, $info;
320 0 0       0 $orig = $port if ! defined $orig; # allow for things like service ports or port 0
321 0 0       0 $fd = ($fd =~ /^(\d+)$/) ? $1 : $self->fatal("Bad file descriptor");
322 0         0 $map{"$host|$orig|$proto|$ipv"}->{$fd} = $port;
323             }
324 0         0 foreach my $sock (@{ $prop->{'sock'} }) {
  0         0  
325 0         0 $sock->log_connect($self);
326 0 0       0 if (my $ref = $map{$sock->hup_string}) {
327 0         0 my ($fd, $port) = each %$ref;
328 0         0 $sock->reconnect($fd, $self, $port);
329 0         0 delete $ref->{$fd};
330 0 0       0 delete $map{$sock->hup_string} if ! keys %$ref;
331             } else {
332 0         0 $self->log(2, "Added new port configuration");
333 0         0 $sock->connect($self);
334             }
335             }
336 0         0 foreach my $str (keys %map) {
337 0         0 foreach my $fd (keys %{ $map{$str} }) {
  0         0  
338 0         0 $self->log(2, "Closing un-mapped port ($str) on fd $fd");
339 0         0 POSIX::close($fd);
340             }
341             }
342 0         0 delete $ENV{'BOUND_SOCKETS'};
343 0         0 $self->{'hup_waitpid'} = 1;
344              
345             } else { # connect to fresh ports
346 25         64 foreach my $sock (@{ $prop->{'sock'} }) {
  25         321  
347 36         237 $sock->log_connect($self);
348 36         184 $sock->connect($self);
349             }
350             }
351              
352 25 100 100     85 if (@{ $prop->{'sock'} } > 1 || $prop->{'multi_port'}) {
  25         473  
353 10         80 $prop->{'multi_port'} = 1;
354 10         421 $prop->{'select'} = IO::Select->new; # if more than one socket we'll need to select on it
355 10         338 $prop->{'select'}->add($_) for @{ $prop->{'sock'} };
  10         142  
356             } else {
357 15         111 $prop->{'multi_port'} = undef;
358 15         233 $prop->{'select'} = undef;
359             }
360             }
361              
362       96 1   sub post_bind_hook {}
363              
364              
365             sub post_bind { # secure the process and background it
366 26     26 1 90 my $self = shift;
367 26         114 my $prop = $self->{'server'};
368              
369 26 50       133 if (! defined $prop->{'group'}) {
    0          
370 26         718 $self->log(1, "Group Not Defined. Defaulting to EGID '$)'");
371 26         253 $prop->{'group'} = $);
372             } elsif ($prop->{'group'} =~ /^([\w.-]+(?:[ ,][\w.-]+)*)$/) {
373 0         0 $prop->{'group'} = eval { get_gid($1) };
  0         0  
374 0 0       0 $self->fatal(my $e = $@) if $@;
375             } else {
376 0         0 $self->fatal("Invalid group \"$prop->{'group'}\"");
377             }
378              
379 26 50       162 if (! defined $prop->{'user'}) {
    0          
380 26         685 $self->log(1, "User Not Defined. Defaulting to EUID '$>'");
381 26         144 $prop->{'user'} = $>;
382             } elsif ($prop->{'user'} =~ /^([\w.-]+)$/) {
383 0         0 $prop->{'user'} = eval { get_uid($1) };
  0         0  
384 0 0       0 $self->fatal(my $e = $@) if $@;
385             } else {
386 0         0 $self->fatal("Invalid user \"$prop->{'user'}\"");
387             }
388              
389             # chown any files or sockets that we need to
390 26 50 33     1039 if ($prop->{'group'} ne $) || $prop->{'user'} ne $>) {
391 0         0 my @chown_files;
392 0         0 push @chown_files, map {$_->NS_port} grep {$_->NS_proto =~ /^UNIX/} @{ $prop->{'sock'} };
  0         0  
  0         0  
  0         0  
393 0 0       0 push @chown_files, $prop->{'pid_file'} if $prop->{'pid_file_unlink'};
394 0 0       0 push @chown_files, $prop->{'lock_file'} if $prop->{'lock_file_unlink'};
395 0 0       0 push @chown_files, @{ $prop->{'chown_files'} || [] };
  0         0  
396 0         0 my $uid = $prop->{'user'};
397 0         0 my $gid = (split /\ /, $prop->{'group'})[0];
398 0         0 foreach my $file (@chown_files){
399 0 0       0 chown($uid, $gid, $file) || $self->fatal("Couldn't chown \"$file\" [$!]");
400             }
401             }
402              
403 26 50       136 if ($prop->{'chroot'}) {
404 0 0       0 $self->fatal("Specified chroot \"$prop->{'chroot'}\" doesn't exist.") if ! -d $prop->{'chroot'};
405 0         0 $self->log(2, "Chrooting to $prop->{'chroot'}");
406 0 0       0 chroot($prop->{'chroot'}) || $self->fatal("Couldn't chroot to \"$prop->{'chroot'}\": $!");
407             }
408              
409             # drop privileges
410 26         93 eval {
411 26 50       242 if ($prop->{'group'} ne $)) {
412 0         0 $self->log(2, "Setting gid to \"$prop->{'group'}\"");
413 0         0 set_gid($prop->{'group'} );
414             }
415 26 50       215 if ($prop->{'user'} ne $>) {
416 0         0 $self->log(2, "Setting uid to \"$prop->{'user'}\"");
417 0         0 set_uid($prop->{'user'});
418             }
419             };
420 26 50       103 if ($@) {
421 0 0       0 if ($> == 0) {
    0          
422 0         0 $self->fatal(my $e = $@);
423             } elsif ($< == 0) {
424 0         0 $self->log(2, "NOTICE: Effective UID changed, but Real UID is 0: $@");
425             } else {
426 0         0 $self->log(2, my $e = $@);
427             }
428             }
429              
430 26         131 $prop->{'requests'} = 0; # record number of request
431              
432 26     0   1115 $SIG{'INT'} = $SIG{'TERM'} = $SIG{'QUIT'} = sub { $self->server_close; };
  0         0  
433 26         312 $SIG{'PIPE'} = 'IGNORE'; # most cases, a closed pipe will take care of itself
434 26         251 $SIG{'CHLD'} = \&sig_chld; # catch children (mainly for Fork and PreFork but works for any chld)
435 26     0   612 $SIG{'HUP'} = sub { $self->sig_hup };
  0         0  
436             }
437              
438             sub sig_chld {
439 0     0 0 0 1 while waitpid(-1, POSIX::WNOHANG()) > 0;
440 0         0 $SIG{'CHLD'} = \&sig_chld;
441             }
442              
443       96 1   sub pre_loop_hook {}
444              
445             sub loop {
446 22     22 1 55 my $self = shift;
447 22         533 while ($self->accept) {
448 31         629 $self->run_client_connection;
449 11 100       94 last if $self->done;
450             }
451             }
452              
453             sub accept {
454 32     32 0 9108 my $self = shift;
455 32         114 my $prop = $self->{'server'};
456              
457 32         87 my $sock = undef;
458 32         111 my $retries = 30;
459 32         191 while ($retries--) {
460 32 100       199 if ($prop->{'multi_port'}) { # with more than one port, use select to get the next one
461 16 50       85 return 0 if $prop->{'_HUP'};
462 16   50     152 $sock = $self->accept_multi_port || next; # keep trying for the rest of retries
463 15 50       102 return 0 if $prop->{'_HUP'};
464 15 50       176 if ($self->can_read_hook($sock)) {
465 0         0 $retries++;
466 0         0 next;
467             }
468             } else {
469 16         49 $sock = $prop->{'sock'}->[0]; # single port is bound - just accept
470             }
471 31 50       185 $self->fatal("Received a bad sock!") if ! defined $sock;
472              
473 31 100       325 if (SOCK_DGRAM == $sock->getsockopt(SOL_SOCKET, SO_TYPE)) { # receive a udp packet
474 1         58 $prop->{'client'} = $sock;
475 1         3 $prop->{'udp_true'} = 1;
476 1         9 $prop->{'udp_peer'} = $sock->recv($prop->{'udp_data'}, $sock->NS_recv_len, $sock->NS_recv_flags);
477              
478             } else { # blocking accept per proto
479 30         1023 delete $prop->{'udp_true'};
480 30         220 $prop->{'client'} = $sock->accept();
481             }
482              
483 31 50       233 return 0 if $prop->{'_HUP'};
484 31 50       350 return 1 if $prop->{'client'};
485              
486 0         0 $self->log(2,"Accept failed with $retries tries left: $!");
487 0         0 sleep(1);
488             }
489              
490 0         0 $self->log(1,"Ran out of accept retries!");
491 0         0 return undef;
492             }
493              
494              
495             sub accept_multi_port {
496 16     16 0 162 my @waiting = shift->{'server'}->{'select'}->can_read();
497 15 50       18560 return undef if ! @waiting;
498 15         491 return $waiting[rand @waiting];
499             }
500              
501       15 1   sub can_read_hook {}
502              
503             sub post_accept {
504 31     31 1 85 my $self = shift;
505 31         112 my $prop = $self->{'server'};
506 31   33     197 my $client = shift || $prop->{'client'};
507              
508 31         91 $prop->{'requests'}++;
509 31 100       257 return if $prop->{'udp_true'}; # no need to do STDIN/STDOUT in UDP
510              
511 30 50       210 if (!$client) {
512 0         0 $self->log(1,"Client socket information could not be determined!");
513 0         0 return;
514             }
515              
516 30 100       659 $client->post_accept() if $client->can("post_accept");
517 30 100       6602 if (! $prop->{'no_client_stdout'}) {
518 29         281 close STDIN; # duplicate some handles and flush them
519 29         742 close STDOUT;
520 29 100 66     873 if ($prop->{'tie_client_stdout'} || ($client->can('tie_stdout') && $client->tie_stdout)) {
    50 100        
521 6 50       271 open STDIN, '<', '/dev/null' or die "Couldn't open STDIN to the client socket: $!";
522 6 50       143 open STDOUT, '>', '/dev/null' or die "Couldn't open STDOUT to the client socket: $!";
523 6 50       111 tie *STDOUT, 'Net::Server::TiedHandle', $client, $prop->{'tied_stdout_callback'} or die "Couldn't tie STDOUT: $!";
524 6 50       22 tie *STDIN, 'Net::Server::TiedHandle', $client, $prop->{'tied_stdin_callback'} or die "Couldn't tie STDIN: $!";
525             } elsif (defined(my $fileno = fileno $prop->{'client'})) {
526 23 50       1061 open STDIN, '<&', $fileno or die "Couldn't open STDIN to the client socket: $!";
527 23 50       454 open STDOUT, '>&', $fileno or die "Couldn't open STDOUT to the client socket: $!";
528             } else {
529 0         0 *STDIN = \*{ $client };
  0         0  
530 0         0 *STDOUT = \*{ $client };
  0         0  
531             }
532 29         283 STDIN->autoflush(1);
533 29         1514 STDOUT->autoflush(1);
534 29         895 select STDOUT;
535             }
536             }
537              
538             sub get_client_info {
539 31     31 1 93 my $self = shift;
540 31         93 my $prop = $self->{'server'};
541 31   33     153 my $client = shift || $prop->{'client'};
542              
543 31 50       199 if ($client->NS_proto =~ /^UNIX/) {
544 0         0 delete @$prop{qw(sockaddr sockport peeraddr peerport peerhost peerhost_rev)};
545 0 0 0     0 $self->log(3, $self->log_time." CONNECT ".$client->NS_proto." Socket: \"".$client->NS_port."\"") if $prop->{'log_level'} && 3 <= $prop->{'log_level'};
546 0         0 return;
547             }
548              
549 31 50       545 if (my $sockname = $client->sockname) {
550 31         1230 $prop->{'sockaddr'} = $client->sockhost;
551 31         2913 $prop->{'sockport'} = $client->sockport;
552             } else {
553 0   0     0 @{ $prop }{qw(sockaddr sockhost sockport)} = ($ENV{'REMOTE_HOST'} || '0.0.0.0', 'inet.test', 0); # commandline
  0         0  
554             }
555              
556 31         1409 my $addr;
557 31 100       226 if (my $peer = $prop->{'udp_true'} ? $prop->{'udp_peer'} : eval { $client->peername }) {
  30 50       1934  
558 31 50       1182 if (my $family = sockaddr_family( $prop->{'peername'} = $peer )) {
559 31 100       147 if ($family == AF_INET) {
    50          
560 19         93 ($prop->{'peerport'}, $addr) = sockaddr_in($peer);
561 19         167 $prop->{'peeraddr'} = inet_ntoa($addr);
562 12         74 } elsif (eval { ipv6_package($self) }) {
563 12         47 ($prop->{'peerport'}, $addr) = sockaddr_in6($peer);
564 12         224 $prop->{'peeraddr'} = inet_ntop($client->sockdomain, $addr);
565             } else {
566 0         0 $self->fatal("No IPv6 support for non-AF_INET sockdomain $@");
567             }
568             }
569             } else {
570 0         0 @{ $prop }{qw(peeraddr peerhost peerport)} = ('0.0.0.0', 'inet.test', 0); # commandline
  0         0  
571             }
572              
573 31         180 delete @$prop{qw(peerhost peerhost_rev)};
574 31 50 33     630 if ($addr && $prop->{'reverse_lookups'}) {
575 0 0 0     0 if ($client->can('peerhostname')) {
    0          
576 0         0 $prop->{'peerhost'} = $client->peerhostname;
577             } elsif ($prop->{'peername'} and my @res = safe_name_info($prop->{'peername'}, 0)) {
578 0 0 0     0 $prop->{'peerhost'} = $res[1] if @res > 1 and !$res[0];
579             } else {
580 0         0 $prop->{'peerhost'} = gethostbyaddr($addr, AF_INET);
581             }
582 0 0 0     0 if ($prop->{'peerhost'} && $prop->{'double_reverse_lookups'}) {
583 0         0 $prop->{'peerhost_rev'} = {map {$_->[0] => 1} get_addr_info($prop->{'peerhost'}, undef, undef, $self)};
  0         0  
584             }
585             }
586              
587             $self->log(3, $self->log_time
588             ." CONNECT ".$client->NS_proto
589             ." Peer: \"[$prop->{'peeraddr'}]:$prop->{'peerport'}\"".($prop->{'peerhost'} ? " ($prop->{'peerhost'}) " : '')
590 31 0 33     586 ." Local: \"[$prop->{'sockaddr'}]:$prop->{'sockport'}\"") if $prop->{'log_level'} && 3 <= $prop->{'log_level'};
    50          
591             }
592              
593       32 1   sub post_accept_hook {}
594              
595             sub allow_deny {
596 32     32 1 85 my $self = shift;
597 32         99 my $prop = $self->{'server'};
598 32   66     115 my $sock = shift || $prop->{'client'};
599              
600             # unix sockets are immune to this check
601 32 50 33     352 return 1 if $sock && $sock->NS_proto =~ /^UNIX/;
602              
603             # work around Net::CIDR::cidrlookup() croaking,
604             # if first parameter is an IPv4 address in IPv6 notation.
605 32 100       171 my $peeraddr = ($prop->{'peeraddr'} =~ /^\s*::ffff:(\d+(?:\.\d+){3})$/) ? $1 : $prop->{'peeraddr'};
606              
607 32 50       163 if ($prop->{'double_reverse_lookups'}) {
608 0 0       0 return 0 if ! $self->double_reverse_lookup($peeraddr, $prop->{'peerhost'}, $prop->{'peerhost_rev'}, $prop->{'peeraddr'})
609             }
610              
611             # if no allow or deny parameters are set, allow all
612 32         282 return 1 if ! @{ $prop->{'allow'} }
613 32         330 && ! @{ $prop->{'deny'} }
614 32         199 && ! @{ $prop->{'cidr_allow'} }
615 32 50 33     78 && ! @{ $prop->{'cidr_deny'} };
  32   33     641  
      33        
616              
617             # if the addr or host matches a deny, reject it immediately
618 0         0 foreach (@{ $prop->{'deny'} }) {
  0         0  
619             return 0 if $prop->{'reverse_lookups'}
620 0 0 0     0 && defined($prop->{'peerhost'}) && $prop->{'peerhost'} =~ /^$_$/;
      0        
621 0 0       0 return 0 if $peeraddr =~ /^$_$/;
622             }
623 0 0       0 if (@{ $prop->{'cidr_deny'} }) {
  0         0  
624 0         0 require Net::CIDR;
625 0 0       0 return 0 if Net::CIDR::cidrlookup($peeraddr, @{ $prop->{'cidr_deny'} });
  0         0  
626             }
627              
628             # if the addr or host isn't blocked yet, allow it if it is allowed
629 0         0 foreach (@{ $prop->{'allow'} }) {
  0         0  
630             return 1 if $prop->{'reverse_lookups'}
631 0 0 0     0 && defined($prop->{'peerhost'}) && $prop->{'peerhost'} =~ /^$_$/;
      0        
632 0 0       0 return 1 if $peeraddr =~ /^$_$/;
633             }
634 0 0       0 if (@{ $prop->{'cidr_allow'} }) {
  0         0  
635 0         0 require Net::CIDR;
636 0 0       0 return 1 if Net::CIDR::cidrlookup($peeraddr, @{ $prop->{'cidr_allow'} });
  0         0  
637             }
638              
639 0         0 return 0;
640             }
641              
642             sub double_reverse_lookup {
643 0     0 1 0 my ($self, $addr, $host, $rev_addrs, $orig_addr) = @_;
644 0   0     0 my $cfg = $self->{'server'}->{'double_reverse_lookups'} || '';
645 0 0       0 if (! $host) {
    0          
646 0         0 $self->log(3, $self->log_time ." Double reverse missing host from addr $addr");
647 0         0 return 0;
648             } elsif (! $rev_addrs) {
649 0         0 $self->log(3, $self->log_time ." Double reverse missing reverse addrs from host $host ($addr)");
650 0         0 return 0;
651             }
652 0 0 0     0 my $extra = ($orig_addr && $orig_addr ne $addr) ? ", orig_addr: $orig_addr" : '';
653 0 0 0     0 if (! $rev_addrs->{$addr} && ! $rev_addrs->{$orig_addr}) {
    0          
    0          
654 0 0       0 $self->log(3, $self->log_time ." Double reverse did not match: addr: $addr, host: $host"
655             .($cfg =~ /detail/i ? ", addrs: (".join(' ', sort keys %$rev_addrs).")$extra" : ''));
656 0         0 return 0;
657             } elsif ($cfg =~ /autofail/i) {
658 0         0 $self->log(3, $self->log_time ." Double reverse autofail: addr: $addr, host: $host, addrs: (".join(' ', sort keys %$rev_addrs).")$extra");
659 0         0 return 0;
660             } elsif ($cfg =~ /debug/) {
661 0         0 $self->log(3, $self->log_time ." Double reverse debug: addr: $addr, host: $host, addrs: (".join(' ', sort keys %$rev_addrs).")$extra");
662             }
663 0         0 return 1;
664             }
665              
666 32     32 1 133 sub allow_deny_hook { 1 } # false to deny request
667              
668       0 1   sub request_denied_hook {}
669              
670             sub process_request { # sample echo server - override for full functionality
671 27     27 1 4130 my $self = shift;
672 27         187 my $prop = $self->{'server'};
673              
674 27 100       152 if ($prop->{'udp_true'}) { # udp echo server
675 1   33     5 my $client = shift || $prop->{'client'};
676 1 50       13 if ($prop->{'udp_data'} =~ /dump/) {
677 0         0 require Data::Dumper;
678 0         0 return $client->send(Data::Dumper::Dumper($self), 0);
679             }
680 1         14 return $client->send("You said \"$prop->{'udp_data'}\"", 0);
681             }
682              
683 26         3318 print "Welcome to \"".ref($self)."\" ($$)\015\012";
684 26         3073 my $previous_alarm = alarm 30;
685 26         85 eval {
686 26     0   729 local $SIG{'ALRM'} = sub { die "Timed Out!\n" };
  0         0  
687 26         24100 while () {
688 22         39342 s/[\r\n]+$//;
689 22         1631 print ref($self),":$$: You said \"$_\"\015\012";
690 22         677 $self->log(5, $_); # very verbose log
691 22 50       587 if (/get\s+(\w+)/) { print "$1: $self->{'server'}->{$1}\015\012" }
  0 50       0  
    100          
    50          
692 0         0 elsif (/dump/) { require Data::Dumper; print Data::Dumper::Dumper($self) }
  0         0  
693 3         9 elsif (/quit/) { last }
694 19         612 elsif (/exit/) { $self->server_close }
695 0         0 alarm 30; # another 30
696             }
697 7         188 alarm($previous_alarm);
698             };
699 7         30 alarm 0;
700 7 50       60 print "Timed Out.\015\012" if $@ eq "Timed Out!\n";
701             }
702              
703       12 1   sub post_process_request_hook {}
704              
705       12 1   sub post_client_connection_hook {}
706              
707             sub post_process_request {
708 12     12 1 33 my $self = shift;
709 12         212 $self->close_client_stdout;
710             }
711              
712             sub close_client_stdout {
713 12     12 0 28 my $self = shift;
714 12         37 my $prop = $self->{'server'};
715 12 100       109 return if $prop->{'udp_true'};
716              
717 11 100       60 if (! $prop->{'no_client_stdout'}) {
718 10 100       42 my $t = tied *STDOUT; if ($t) { undef $t; untie *STDOUT };
  10         35  
  4         8  
  4         60  
719 10 100       26 $t = tied *STDIN; if ($t) { undef $t; untie *STDIN };
  10         45  
  4         7  
  4         11  
720 10 50       635 open(STDIN, '<', '/dev/null') || die "Cannot read /dev/null [$!]";
721 10 50       359 open(STDOUT, '>', '/dev/null') || die "Cannot write /dev/null [$!]";
722             }
723 11         337 $prop->{'client'}->close;
724             }
725              
726             sub done {
727 9     9 0 42 my $self = shift;
728 9 50       56 $self->{'server'}->{'done'} = shift if @_;
729 9         74 return $self->{'server'}->{'done'};
730             }
731              
732       5 1   sub pre_fork_hook {}
733       4 1   sub register_child {}
734       1 1   sub child_init_hook {}
735       1 1   sub child_finish_hook {}
736              
737             sub run_dequeue { # fork off a child process to handle dequeuing
738 0     0 0 0 my $self = shift;
739 0         0 $self->pre_fork_hook('dequeue');
740 0         0 my $pid = fork;
741 0 0       0 $self->fatal("Bad fork [$!]") if ! defined $pid;
742 0 0       0 if (!$pid) { # child
743             $SIG{'INT'} = $SIG{'TERM'} = $SIG{'QUIT'} = $SIG{'HUP'} = sub {
744 0     0   0 $self->child_finish_hook('dequeue');
745 0         0 exit;
746 0         0 };
747 0         0 $SIG{'PIPE'} = $SIG{'TTIN'} = $SIG{'TTOU'} = 'DEFAULT';
748 0         0 $self->child_init_hook('dequeue');
749 0         0 $self->dequeue();
750 0         0 $self->child_finish_hook('dequeue');
751 0         0 exit;
752             }
753 0         0 $self->log(4, "Running dequeue child $pid");
754              
755             $self->{'server'}->{'children'}->{$pid}->{'status'} = 'dequeue'
756 0 0       0 if $self->{'server'}->{'children'};
757 0         0 $self->register_child($pid, 'dequeue');
758             }
759              
760 11     11 0 18307 sub default_port { 20203 }
761              
762       0 0   sub dequeue {}
763              
764       25 1   sub pre_server_close_hook {}
765              
766             sub server_close {
767 25     25 1 152 my ($self, $exit_val) = @_;
768 25         85 my $prop = $self->{'server'};
769              
770 25         685 $SIG{'INT'} = 'DEFAULT';
771              
772             ### if this is a child process, signal the parent and close
773             ### normally the child shouldn't, but if they do...
774             ### otherwise the parent continues with the shutdown
775             ### this is safe for nonstandard forked child processes
776             ### as they will not have server_close as a handler
777 25 50 66     528 if (defined($prop->{'ppid'})
      33        
778             && $prop->{'ppid'} != $$
779             && ! defined($prop->{'no_close_by_child'})) {
780 0         0 $self->close_parent;
781 0         0 exit;
782             }
783              
784 25         479 $self->pre_server_close_hook;
785              
786 25         233 $self->log(2, $self->log_time . " Server closing!");
787              
788 25 0 33     172 if ($prop->{'kind_quit'} && $prop->{'children'}) {
789 0         0 $self->log(3, "Attempting a slow shutdown");
790 0         0 $prop->{$_} = 0 for qw(min_servers max_servers);
791 0         0 $self->hup_children; # send children signal to finish up
792 0         0 while (1) {
793 0         0 Net::Server::SIG::check_sigs();
794 0 0       0 $self->coordinate_children if $self->can('coordinate_children');
795 0 0       0 last if !keys %{$self->{'server'}->{'children'}};
  0         0  
796 0         0 sleep 1;
797             }
798             }
799              
800 25 50 33     358 if ($prop->{'_HUP'} && $prop->{'leave_children_open_on_hup'}) {
801 0         0 $self->hup_children;
802              
803             } else {
804 25 100       212 $self->close_children() if $prop->{'children'};
805 25         635 $self->post_child_cleanup_hook;
806             }
807              
808 25 50 66     316 if (defined($prop->{'lock_file'})
      66        
809             && -e $prop->{'lock_file'}
810             && defined($prop->{'lock_file_unlink'})) {
811 2 50       563 unlink($prop->{'lock_file'}) || $self->log(1, "Couldn't unlink \"$prop->{'lock_file'}\" [$!]");
812             }
813 25 0 33     305 if (defined($prop->{'pid_file'})
      33        
      0        
814             && -e $prop->{'pid_file'}
815             && !$prop->{'_HUP'}
816             && defined($prop->{'pid_file_unlink'})) {
817 0 0       0 unlink($prop->{'pid_file'}) || $self->log(1, "Couldn't unlink \"$prop->{'pid_file'}\" [$!]");
818             }
819 25 50       178 if (defined($prop->{'sem'})) {
820 0         0 $prop->{'sem'}->remove();
821             }
822              
823 25 50       216 if ($prop->{'_HUP'}) {
824 0         0 $self->restart_close_hook();
825 0         0 $self->hup_server; # execs at the end
826             }
827              
828 25         525 $self->shutdown_sockets;
829 25 50       235 return $self if $prop->{'no_exit_on_close'};
830 25         549 $self->server_exit($exit_val);
831             }
832              
833             sub server_exit {
834 25     25 1 177 my ($self, $exit_val) = @_;
835 25   50     10490 exit($exit_val || 0);
836             }
837              
838             sub shutdown_sockets {
839 25     25 1 68 my $self = shift;
840 25         84 my $prop = $self->{'server'};
841              
842 25         63 foreach my $sock (@{ $prop->{'sock'} }) { # unlink remaining socket files (if any)
  25         219  
843 34         1006 $sock->shutdown(2);
844 34 50       1321 unlink $sock->NS_port if $sock->NS_proto =~ /^UNIX/;
845             }
846              
847 25         932 $prop->{'sock'} = []; # delete the sock objects
848 25         275 return 1;
849             }
850              
851             ### Allow children to send INT signal to parent (or use another method)
852             ### This method is only used by forking servers
853             sub close_parent {
854 0     0 0 0 my $self = shift;
855 0         0 my $prop = $self->{'server'};
856 0 0       0 croak "Missing parent pid (ppid)" if ! $prop->{'ppid'};
857 0         0 kill 'INT', $prop->{'ppid'};
858             }
859              
860             ### SIG INT the children
861             ### This method is only used by forking servers (ie Fork, PreFork)
862             sub close_children {
863 3     3 0 17 my $self = shift;
864 3         13 my $prop = $self->{'server'};
865 3 50 50     59 return unless $prop->{'children'} && scalar keys %{ $prop->{'children'} };
  3         30  
866              
867 3         12 foreach my $pid (keys %{ $prop->{'children'} }) {
  3         50  
868 4         32 $self->log(4, "Kill TERM pid $pid");
869 4 50 33     172 if (kill('TERM', $pid) || ! kill(0, $pid)) { # if it is killable, kill it
870 4         88 $self->delete_child($pid);
871             }
872             }
873              
874 3         46 1 while waitpid(-1, POSIX::WNOHANG()) > 0;
875             }
876              
877              
878 0     0 0 0 sub is_prefork { 0 }
879              
880             sub hup_children {
881 0     0 0 0 my $self = shift;
882 0         0 my $prop = $self->{'server'};
883 0 0 0     0 return unless defined $prop->{'children'} && scalar keys %{ $prop->{'children'} };
  0         0  
884 0 0       0 return if ! $self->is_prefork;
885 0         0 $self->log(2, "Sending children hup signal");
886              
887 0         0 for my $pid (keys %{ $prop->{'children'} }) {
  0         0  
888 0         0 $self->log(4, "Kill HUP pid $pid");
889 0 0       0 kill('HUP', $pid) or $self->log(2, "Failed to kill pid $pid: $!");
890             }
891             }
892              
893       25 1   sub post_child_cleanup_hook {}
894              
895             ### handle sig hup
896             ### this will prepare the server for a restart via exec
897             sub sig_hup {
898 0     0 0 0 my $self = shift;
899 0         0 my $prop = $self->{'server'};
900              
901 0         0 $self->log(2, "Received a SIG HUP");
902              
903 0         0 my $i = 0;
904 0         0 my @fd;
905 0         0 $prop->{'_HUP'} = [];
906 0         0 foreach my $sock (@{ $prop->{'sock'} }) {
  0         0  
907 0   0     0 my $fd = POSIX::dup($sock->fileno) || $self->fatal("Cannot duplicate the socket [$!]");
908              
909             # hold on to the socket copy until exec;
910             # just temporary: any socket domain will do,
911             # forked process will decide to use IO::Socket::IP or IO::Socket::INET6 if necessary
912 0         0 $prop->{'_HUP'}->[$i] = IO::Socket::INET->new;
913 0 0       0 $prop->{'_HUP'}->[$i]->fdopen($fd, 'w') || $self->fatal("Cannot open to file descriptor [$!]");
914              
915             # turn off the FD_CLOEXEC bit to allow reuse on exec
916 0         0 require Fcntl;
917 0         0 $prop->{'_HUP'}->[$i]->fcntl(Fcntl::F_SETFD(), my $flags = "");
918              
919 0         0 push @fd, $fd .'|'. $sock->hup_string; # save file-descriptor and host|port|proto|ipv
920              
921 0         0 $sock->close();
922 0         0 $i++;
923             }
924 0         0 delete $prop->{'select'}; # remove any blocking obstacle
925 0         0 $ENV{'BOUND_SOCKETS'} = join "; ", @fd;
926              
927 0 0 0     0 if ($prop->{'leave_children_open_on_hup'} && scalar keys %{ $prop->{'children'} }) {
  0         0  
928 0         0 $ENV{'HUP_CHILDREN'} = join "\n", map {"$_\t$prop->{'children'}->{$_}->{'status'}"} sort keys %{ $prop->{'children'} };
  0         0  
  0         0  
929             }
930             }
931              
932              
933             sub hup_server {
934 0     0 0 0 my $self = shift;
935 0         0 $self->log(0, $self->log_time()." Re-exec server during HUP");
936 0         0 delete @ENV{$self->hup_delete_env_keys};
937 0         0 exec @{ $self->commandline };
  0         0  
938             }
939              
940 0     0 0 0 sub hup_delete_env_keys { return qw(PATH) }
941              
942       0 1   sub restart_open_hook {} # this hook occurs if a server has been HUP'ed it occurs just before opening to the fileno's
943              
944       0 1   sub restart_close_hook {} # this hook occurs if a server has been HUP'ed it occurs just before exec'ing the server
945              
946             ###----------------------------------------------------------###
947              
948             sub fatal {
949 0     0 0 0 my ($self, $error) = @_;
950 0         0 my ($package, $file, $line) = caller;
951 0         0 $self->fatal_hook($error, $package, $file, $line);
952 0         0 $self->log(0, $self->log_time ." $error\n at line $line in file $file");
953 0         0 $self->server_close(1);
954             }
955              
956       0 1   sub fatal_hook {}
957              
958             ###----------------------------------------------------------###
959              
960             sub log {
961 184     184 1 626 my ($self, $level, $msg, @therest) = @_;
962 184         573 my $prop = $self->{'server'};
963 184 50       611 return if ! $prop->{'log_level'};
964 184 100 66     2612 return if $level =~ /^\d+$/ && $level > $prop->{'log_level'};
965 146 50       383 $msg = sprintf($msg, @therest) if @therest; # if multiple arguments are passed, assume that the first is a format string
966              
967 146 100       513 if ($prop->{'log_function'}) {
968 5 50       11 return if eval { $prop->{'log_function'}->($level, $msg); 1 };
  5         29  
  5         40  
969 0         0 my $err = $@;
970 0 0 0     0 if ($prop->{'log_class'} && $prop->{'log_class'}->can('handle_error')) {
971 0         0 $prop->{'log_class'}->handle_log_error($self, $err, [$level, $msg]);
972             } else {
973 0         0 $self->handle_log_error($err, [$level, $msg]);
974             }
975             }
976              
977 141 50       721 return if $level !~ /^\d+$/;
978 141         1041 $self->write_to_log_hook($level, $msg);
979             }
980              
981              
982 0     0 0 0 sub handle_log_error { my ($self, $error) = @_; die $error }
  0         0  
983 0     0 1 0 sub handle_syslog_error { &handle_log_error }
984              
985             sub write_to_log_hook {
986 141     141 1 533 my ($self, $level, $msg) = @_;
987 141         301 my $prop = $self->{'server'};
988 141         320 chomp $msg;
989 141         535 $msg =~ s/([^\n\ -\~])/sprintf("%%%02X",ord($1))/eg;
  0         0  
990              
991 141 50       570 if ($prop->{'log_file'}) {
    50          
992 0         0 print _SERVER_LOG $msg, "\n";
993             } elsif ($prop->{'setsid'}) {
994             # do nothing ?
995             } else {
996 141         634 my $old = select STDERR;
997 141         1219 print $msg. "\n";
998 141         1069 select $old;
999             }
1000             }
1001              
1002              
1003             sub log_time {
1004 120     120 0 5332 my ($sec,$min,$hour,$day,$mon,$year) = localtime;
1005 120         3351 return sprintf "%04d/%02d/%02d-%02d:%02d:%02d", $year + 1900, $mon + 1, $day, $hour, $min, $sec;
1006             }
1007              
1008             ###----------------------------------------------------------###
1009              
1010             sub options {
1011 132     132 0 538 my $self = shift;
1012 132   50     570 my $ref = shift || {};
1013 132         384 my $prop = $self->{'server'};
1014              
1015 132         1505 foreach (qw(port host proto ipv allow deny cidr_allow cidr_deny)) {
1016 1056 100       2430 if (! defined $prop->{$_}) {
    100          
1017 760         3595 $prop->{$_} = [];
1018             } elsif (! ref $prop->{$_}) {
1019 8         21 $prop->{$_} = [$prop->{$_}]; # nicely turn us into an arrayref if we aren't one already
1020             }
1021 1056         2395 $ref->{$_} = $prop->{$_};
1022             }
1023              
1024 132         382 foreach (qw(conf_file
1025             user group chroot log_level
1026             log_file log_function pid_file background setsid
1027             listen ipv6_package reverse_lookups double_reverse_lookups
1028             no_close_by_child
1029             no_client_stdout tie_client_stdout tied_stdout_callback tied_stdin_callback
1030             leave_children_open_on_hup
1031             )) {
1032 2640         10200 $ref->{$_} = \$prop->{$_};
1033             }
1034 132         467 return $ref;
1035             }
1036              
1037              
1038             ### routine for parsing commandline, module, and conf file
1039             ### method has the benefit of leaving unused arguments in @ARGV
1040             sub process_args {
1041 160     160 0 651 my ($self, $args, $template) = @_;
1042 160 100 66     1610 $self->options($template = {}) if ! $template || ! ref $template;
1043 160 0 66     1409 if (!$_[2] && !scalar(keys %$template) && !$self->{'server'}->{'_no_options'}++) {
      33        
1044 0         0 warn "Configuration options were empty - skipping any commandline, config file, or run argument parsing.\n";
1045             }
1046              
1047             # we want subsequent calls to not overwrite or add to previously set values so that command line arguments win
1048 160         326 my %previously_set;
1049 160         716 foreach (my $i = 0; $i < @$args; $i++) {
1050 422 100 100     4123 if ($args->[$i] =~ /^(?:--)?(\w+)(?:[=\ ](\S+))?$/
1051             && exists $template->{$1}) {
1052 404         1287 my ($key, $val) = ($1, $2);
1053 404         758 splice @$args, $i, 1;
1054 404 100       912 if (! defined $val) {
1055 401 50 66     2731 if ($i > $#$args
      33        
1056             || ($args->[$i] && $args->[$i] =~ /^--\w+/)) {
1057 0         0 $val = 1; # allow for options such as --setsid
1058             } else {
1059 401         971 $val = splice @$args, $i, 1;
1060 401 50 100     1445 $val = $val->[0] if ref($val) eq 'ARRAY' && @$val == 1 && ref($template->{$key}) ne 'ARRAY';
      66        
1061             }
1062             }
1063 404         583 $i--;
1064 404 100       1155 $val =~ s/%([A-F0-9])/chr(hex $1)/eig if ! ref $val;
  0         0  
1065              
1066 404 100       1073 if (ref $template->{$key} eq 'ARRAY') {
1067 240 100       613 if (! defined $previously_set{$key}) {
1068 198         305 $previously_set{$key} = scalar @{ $template->{$key} };
  198         676  
1069             }
1070 240 100       820 next if $previously_set{$key};
1071 228 100       461 push @{ $template->{$key} }, ref($val) eq 'ARRAY' ? @$val : $val;
  228         1414  
1072             } else {
1073 164 100       636 if (! defined $previously_set{$key}) {
1074 146 100       351 $previously_set{$key} = defined(${ $template->{$key} }) ? 1 : 0;
  146         593  
1075             }
1076 164 100       489 next if $previously_set{$key};
1077 137 50       634 croak "Found multiple values on the configuration item \"$key\" which expects only one value" if ref($val) eq 'ARRAY';
1078 137         253 ${ $template->{$key} } = $val;
  137         849  
1079             }
1080             }
1081             }
1082             }
1083              
1084             sub _read_conf {
1085 9     9   21 my ($self, $file) = @_;
1086 9         16 my @args;
1087 9 50       44 $file = ($file =~ m|^([\w\.\-\/\\\:]+)$|) ? $1 : $self->fatal("Unsecure filename \"$file\"");
1088 9 50       463 open my $fh, '<', $file or do {
1089 0 0       0 $self->fatal("Couldn't open conf \"$file\" [$!]") if $ENV{'BOUND_SOCKETS'};
1090 0         0 warn "Couldn't open conf \"$file\" [$!]\n";
1091             };
1092 9         265 while (defined(my $line = <$fh>)) {
1093 189 100       446 $line = $1 if $line =~ /(.*?)(?
1094 189         263 $line =~ s/\\#/#/g;
1095 189 100       748 push @args, $1, $2 if $line =~ m/^\s*((?:--)?\w+)(?:\s*[=:]\s*|\s+)(.+)/;
1096             }
1097 9         90 close $fh;
1098 9         56 return \@args;
1099             }
1100              
1101             ###----------------------------------------------------------------###
1102              
1103       0 0   sub other_child_died_hook {}
1104              
1105       4 0   sub delete_child_hook {}
1106              
1107             sub delete_child {
1108 4     4 0 17 my ($self, $pid) = @_;
1109 4         21 my $prop = $self->{'server'};
1110              
1111 4 50       19 return $self->other_child_died_hook($pid) if ! exists $prop->{'children'}->{$pid};
1112              
1113             # prefork server check to clear child communication
1114 4 100       20 if ($prop->{'child_communication'}) {
1115 1 50       16 if ($prop->{'children'}->{$pid}->{'sock'}) {
1116 1         9 $prop->{'child_select'}->remove($prop->{'children'}->{$pid}->{'sock'});
1117 1         135 $prop->{'children'}->{$pid}->{'sock'}->close;
1118             }
1119             }
1120              
1121 4         335 $self->delete_child_hook($pid); # user customizable hook
1122              
1123 4         38 delete $prop->{'children'}->{$pid};
1124             }
1125              
1126             # send signal to all children - used by forking servers
1127             sub sig_pass {
1128 0     0 0 0 my ($self, $sig) = @_;
1129 0         0 foreach my $chld (keys %{ $self->{'server'}->{'children'} }) {
  0         0  
1130 0         0 $self->log(4, "signaling $chld with $sig" );
1131 0 0       0 kill($sig, $chld) || $self->log(1, "child $chld not signaled with $sig");
1132             }
1133             }
1134              
1135             # register sigs to allow passthrough to children
1136             sub register_sig_pass {
1137 3     3 0 16 my $self = shift;
1138 3   50     40 my $ref = $self->{'server'}->{'sig_passthrough'} || [];
1139 3 50       28 $ref = [$ref] if ! ref $ref;
1140 3 50       13 $self->fatal('invalid sig_passthrough') if ref $ref ne 'ARRAY';
1141 3 50       17 return if ! @$ref;
1142 0         0 $self->log(4, "sig_passthrough option found");
1143 0         0 require Net::Server::SIG;
1144 0         0 foreach my $sig (map {split /\s*,\s*/, $_} @$ref) {
  0         0  
1145 0         0 my $code = Net::Server::SIG::sig_is_registered($sig);
1146 0 0       0 if ($code) {
1147 0         0 $self->log(2, "Installing passthrough for $sig even though it is already registered.");
1148             } else {
1149 0 0       0 $code = ref($SIG{$sig}) eq 'CODE' ? $SIG{$sig} : undef;
1150             }
1151 0 0   0   0 Net::Server::SIG::register_sig($sig => sub { $self->sig_pass($sig); $code->($sig) if $code; });
  0         0  
  0         0  
1152 0         0 $self->log(2, "Installed passthrough for $sig");
1153             }
1154             }
1155              
1156             ###----------------------------------------------------------------###
1157              
1158             package Net::Server::TiedHandle;
1159 12     12   116 sub TIEHANDLE { my $pkg = shift; return bless [@_], $pkg }
  12         103  
1160 3 50   3   17 sub READLINE { my $s = shift; $s->[1] ? $s->[1]->($s->[0], 'getline', @_) : $s->[0]->getline }
  3         50  
1161 0 0   0   0 sub SAY { my $s = shift; $s->[1] ? $s->[1]->($s->[0], 'say', @_) : $s->[0]->say(@_) }
  0         0  
1162 11 100   11   359 sub PRINT { my $s = shift; $s->[1] ? $s->[1]->($s->[0], 'print', @_) : $s->[0]->print(@_) }
  11         123  
1163 0 0   0   0 sub PRINTF { my $s = shift; $s->[1] ? $s->[1]->($s->[0], 'printf', @_) : $s->[0]->printf(@_) }
  0         0  
1164 1 50   1   34 sub READ { my $s = shift; $s->[1] ? $s->[1]->($s->[0], 'read', @_) : $s->[0]->read(@_) }
  1         9  
1165 1 50   1   20 sub WRITE { my $s = shift; $s->[1] ? $s->[1]->($s->[0], 'write', @_) : $s->[0]->write(@_) }
  1         13  
1166 0 0   0     sub SYSREAD { my $s = shift; $s->[1] ? $s->[1]->($s->[0], 'sysread', @_) : $s->[0]->sysread(@_) }
  0            
1167 0 0   0     sub SYSWRITE { my $s = shift; $s->[1] ? $s->[1]->($s->[0], 'syswrite', @_) : $s->[0]->syswrite(@_) }
  0            
1168 0 0   0     sub SEEK { my $s = shift; $s->[1] ? $s->[1]->($s->[0], 'seek', @_) : $s->[0]->seek(@_) }
  0            
1169       0     sub BINMODE {}
1170       0     sub FILENO {}
1171 0 0   0     sub CLOSE { my $s = shift; $s->[1] ? $s->[1]->($s->[0], 'close', @_) : $s->[0]->close(@_) }
  0            
1172              
1173              
1174             1;
1175              
1176             ### The documentation is in Net/Server.pod