File Coverage

blib/lib/NetServer/Generic.pm
Criterion Covered Total %
statement 216 442 48.8
branch 61 218 27.9
condition 16 58 27.5
subroutine 25 33 75.7
pod 1 11 9.0
total 319 762 41.8


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2              
3             package NetServer::Generic;
4              
5 14     14   110 use Carp;
  14         30  
  14         1818  
6 14     14   19500 use Data::Dumper;
  14         143170  
  14         1022  
7 14     14   112 use Exporter;
  14         28  
  14         402  
8 14     14   70 use Fcntl;
  14         22  
  14         3758  
9 14     14   10864 use IO::File;
  14         142710  
  14         3848  
10 14     14   11642 use IO::Socket;
  14         244018  
  14         64  
11 14     14   8218 use IO::Handle;
  14         36  
  14         470  
12 14     14   10692 use IO::Select;
  14         23048  
  14         588  
13 14     14   1202810 use IO::Pipe;
  14         22392  
  14         664  
14 14     14   14266 use POSIX qw(mkfifo BUFSIZ EWOULDBLOCK WNOHANG);
  14         121380  
  14         130  
15 14     14   21024 use Socket;
  14         34  
  14         16722  
16 14     14   28694 use Time::HiRes qw(gettimeofday tv_interval);
  14         26070  
  14         74  
17 14     14   25628 use Tie::RefHash;
  14         29982  
  14         828  
18              
19             BEGIN {
20 14 50   14   876 if (! eval "require Thread") {
21             # want warnings? uncomment the next line
22             # warn "Could not import Thread.pm: $@\n";
23 14         4242 $MAIN::no_thread = 1;
24             } else {
25 0         0 Thread->import();
26             }
27             }
28              
29             @ISA = (qw(NetServer));
30              
31             $VERSION = "1.03";
32              
33 14     14   84 use strict;
  14         28  
  14         91886  
34              
35              
36             =pod
37              
38             =head1 NAME
39              
40             Server - generic TCP/IP server class
41              
42             =head1 SYNOPSIS
43              
44             my $server_cb = sub {
45             my ($s) = shift ;
46             print STDOUT "Echo server: type bye to quit, exit ",
47             "to kill the server.\n\n" ;
48             while (defined ($tmp = )) {
49             return if ($tmp =~ /^bye/i);
50             $s->quit() if ($tmp =~ /^exit/i);
51             print STDOUT "You said:>$tmp\n";
52             }
53             my ($foo) = new NetServer::Generic;
54             $foo->port(9000);
55             $foo->callback($server_cb);
56             $foo->mode("forking");
57             print "Starting server\n";
58             $foo->run();
59              
60             =head1 DESCRIPTION
61              
62             C provides a (very) simple server daemon for TCP/IP
63             processes. It is intended to free the programmer from having to think
64             too hard about networking issues so that they can concentrate on
65             doing something useful.
66              
67             The C object accepts the following methods, which
68             configure various aspects of the new server:
69              
70             =over 4
71              
72             =item port
73              
74             The port to listen on.
75              
76             =item hostname
77              
78             The local address to bind to. If no address is specified, listens for
79             any connection on the designated port.
80              
81             =item listen
82              
83             Queue size for listen.
84              
85             =item proto
86              
87             Protocol we're listening to (defaults to tcp)
88              
89             =item timeout
90              
91             Timeout value (see L)
92              
93             =item allowed
94              
95             list of IP addresses or hostnames that are explicitly allowed to connect
96             to the server. If empty, the default policy is to allow connections from
97             anyone not in the 'forbidden' list.
98              
99             NOTE: IP addresses or hostnames may be specified as perl regular
100             expressions; for example 154\.153\.4\..* matches any IP address
101             beginning with '154.153.4.';
102             .*antipope\.org matches any hostname in the antipope.org domain.
103              
104             =item forbidden
105              
106             list of IP addresses or hostnames that are refused permission to
107             connect to the server. If empty, the default policy is to refuse
108             connections from anyone not in the 'allowed' list (unless the
109             allowed list is empty, in which case anyone may connect).
110              
111             =item callback
112              
113             Coderef to a subroutine which handles incoming connections (called
114             with one parameter -- a C object which can be used
115             to shut down the session).
116              
117             =item mode
118              
119             Can be one of B, B
120             B, or B.
121              
122             By default, B mode is selected.
123              
124             B mode is selected, the server handles requests by forking a
125             child process to service them. If B
126             uses the C class to implement a simple non-forking server.
127              
128             The select-based server may block on i/o on a heavily-loaded system. If
129             you need to do non-blocking i/o you should look at NetServer::FastSelect.
130              
131             The B mode is special; it indicates that rather than sitting
132             around waiting for an incoming connection, the server is itself a
133             TCP/IP client. In client mode, C is the B host to
134             connect to and C is the remote port to open. The callback
135             routine is used, as elsewhere, but it should be written as for a
136             client -- i.e. it should issue a request or command, then read.
137             An additional method exists for client mode: C. C
138             expects a coderef as a parameter. This coderef is executed
139             before the client-mode server spawns a child; if it returns a non-zero
140             value the child is forked and opens a client connection to the target
141             host, otherwise the server exits. The trigger method may be used to
142             sleep for a random interval then return 1 (so that repeated clients
143             are spawned at random intervals), or fork several children (on a one-
144             time-only basis) then work as above (so that several clients poke at
145             the target server on a random basis). The default trigger method
146             returns 1 immediately the first time it is called, then returns 0 --
147             this means that the client makes a single connection to the target
148             host, invokes the callback routine, then exits. (See the test examples
149             which come with this module for examples of how to use client mode.)
150              
151             Note that client mode relies on the fork() system call.
152              
153             The B mode indicates that multithreading will be used to
154             service requests. This feature requires Perl 5.005 or higher and a
155             native threads library to run, so it's not 100% portable). Moreover,
156             it's unreliable! Don't use this mode unless you're prepared to do some
157             debugging.
158              
159             The B mode indicates that the server will bind to the
160             designated port, then fork repeatedly up to C<$start_servers> times
161             (where C is a scalar parameter to C).
162             Each child then enters a select-based loop. (i.e. run_select), but exits
163             after handling C<$server_lifespan> transactions (where C
164             is another parameter to C). Every time a child
165             handles a transaction it writes its PID and generation number down a pipe
166             to the parent process, with a message when it exits. The parent keeps
167             track of how many servers are in use and fires up extra children (up to
168             C<$max_servers>) if the number in use leaves less than C<$min_spare_servers>
169             free. See the example B for a minimal HTTP 0.9 server
170             implemented using the B mode.
171              
172              
173             =back
174              
175             Of these, the C method is most important; it specifies
176             a reference to a subroutine which effectively does whatever the
177             server does.
178              
179             A callback subroutine is a normal Perl subroutine. It is invoked
180             with STDIN and STDOUT attached to an C object,
181             so that reads from STDIN get information from the client, and writes
182             to STDOUT send information to the client. Note that both STDIN and
183             STDOUT are unbuffered. In addition, a C object is
184             passed as an argument (but the C is free to ignore it).
185              
186             Your server reads and writes data via the socket as if it is the
187             standard input and standard output filehandles; for example:
188              
189             while (defined ($tmp = )) { # read a line from the socket
190              
191             print STDOUT "You said: $tmp\n"; # print something to the socket
192              
193             (See C and C for more information on this.)
194              
195             If you're not familiar with sockets, don't get too fresh and try to
196             close or seek on STDIN or STDOUT; just treat them like a file.
197              
198             The server object is not strictly necessary in the callback, but comes
199             in handy: you can shut down the server completely by calling the
200             C method.
201            
202             When writing a callback subroutine, remember to define some condition under
203             which you return!
204              
205             Here's a slightly more complex server example:
206              
207              
208             # minimal http server (HTTP/0.9):
209             # this is a REALLY minimal HTTP server. It only understands GET
210             # requests, does no header parsing whatsoever, and doesn't understand
211             # relative addresses! Nor does it understand CGI scripts. And it ain't
212             # suitable as a replacement for Apache (at least, not any time soon :).
213             # The base directory for the server and the default
214             # file name are defined in B, which maps URLs to
215             # absolute pathnames. The server code itself is defined in the
216             # closure B<$http>, which shows how simple it is to write a server
217             # using this module.
218              
219             sub url_to_file($) {
220             # for a given URL, turn it into an absolute pathname
221             my ($u) = shift ; # incoming URL fragment from GET request
222             my ($f) = ""; # file pathname to return
223             my ($htbase) = "/usr/local/etc/httpd/docs/";
224             my ($htdefault) = "index.html";
225             chop $u;
226             if ($u eq "/") {
227             $f = $htbase . $htdefault;
228             return $f;
229             } else {
230             if ($u =~ m|^/.+|) {
231             $f = $htbase; chop $f;
232             $f .= $u;
233             } elsif ($u =~ m|[^/]+|) {
234             $f = $htbase . $u;
235             }
236             if ($u =~ m|.+/$|) {
237             $f .= $htdefault;
238             }
239             if ($f =~ /\.\./) {
240             my (@path) = split("/", $f);
241             my ($buff, $acc) = "";
242             shift @path;
243             while ($buff = shift @path) {
244             my ($tmp) = shift @path;
245             if ($tmp ne '..') {
246             unshift @path, $tmp;
247             $acc .= "/$buff";
248             }
249             }
250             $f = $acc;
251             }
252             }
253             return $f;
254             }
255              
256             my ($http) = sub {
257             my ($fh) = shift ;
258             while (defined ($tmp = )) {
259             chomp $tmp;
260             if ($tmp =~ /^GET\s+(.*)$/i) {
261             $getfile = $1;
262             $getfile = url_to_file($getfile);
263             print STDERR "Sending $getfile\n";
264             my ($in) = new IO::File();
265             if ($in->open("<$getfile") ) {
266             $in->autoflush(1);
267             print STDOUT "Content-type: text/html\n\n";
268             while (defined ($line = <$in>)) {
269             print STDOUT $line;
270             }
271             } else {
272             print STDOUT "404: File not found\n\n";
273             }
274             }
275             return 0;
276             }
277             };
278              
279             # main program starts here
280              
281             my (%config) = ("port" => 9000,
282             "callback" => $http,
283             "hostname" => "public.antipope.org");
284              
285             my ($allowed) = ['.*antipope\.org',
286             '.*localhost.*'];
287              
288             my ($forbidden) = [ '194\.205\.10\.2'];
289              
290             my ($foo) = new Server(%config); # create new http server bound to port
291             # 9000 of public.antipope.org
292             $foo->allowed($allowed); # who is allowed to connect to us
293             $foo->forbidden($forbidden); # who is refused access
294             print "Starting http server on port 9000\n";
295             $foo->run();
296             exit 0;
297              
298              
299             =head2 Additional methods
300              
301             C provides a couple of extra methods.
302              
303             =over 4
304              
305             =item peer()
306              
307             The B method returns a reference to a two-element list containing
308             the hostname and IP address of the host at the other end of the socket.
309             If called before a connection has been received, its value will be undefined.
310             (Don't try to assign values via B unless you want to confuse the
311             allowed/forbidden checking code!)
312              
313             =item quit()
314              
315             The B method attempts to shut down a server. If running as a forking
316             service, it does so by sending a kill -15 to the parent process. If running
317             as a select-based service it returns from B.
318              
319             =item start_servers()
320              
321             In B mode, specifies how many child servers to start up.
322              
323             =item max_servers()
324              
325             In B mode, specifies the maximum number of children to spawn
326             under load.
327              
328             =item min_spare_servers()
329              
330             In B mode, specifies a number of spare (inactive) child
331             servers; if we drop below this level (due to load), the parent will spawn
332             additional children (up to a maximum of B) until we go back
333             over B.
334              
335             =item server_lifespan()
336              
337             In B server mode, child servers run as select servers. After
338             B connections they will commit suicide and be replaced by
339             the parent. If B is set to 1, children will effectively
340             run once then exit (like a forking server). For purposes of insanity,
341             a lifespan of 0 is treated like a lifespan of 1.
342              
343             =item servername()
344              
345             In the B server, unless you I tell the server to bind
346             to a named host, it will accept all incoming connections. Within a client,
347             you may need to know what local IP address an incoming connection was
348             intended for. The C method can be invoked within the child
349             server's callback and returns a two-element arrayref containing the port
350             and IP address that the connection came in on. For example, in the client:
351              
352             my $callback = sub {
353             my $server = shift;
354             my ($server_port, $server_addr) = @{ $server->servername() };
355             print "Connection on $server_addr:$server_port\n";
356              
357              
358             =back
359              
360             =head2 Types of server
361              
362             A full discussion of internet servers is well beyond the scope of this man
363             page. Beginners may want to start with a source like L
364             Programming> (which provides a simple, lucid discussion); more advanced
365             readers may find Stevens' L
366             useful.
367              
368             In general, on non-threaded systems, a forking server is slightly less
369             efficient than a select-based server (and uses up lots of PIDs). On the other
370             hand, a select-based server is not a good solution to high workloads or
371             time-consuming processes such as providing an NNTP news feed to an online
372             newsreader.
373              
374             A major issue with the select-based server code in this release is that
375             the IO::Select based server cannot know that a socket is ready until some
376             data is received over it. (It calls B to detect sockets waiting
377             to be read from.) Thus, it is not suitable for writing servers like
378             which emit status information without first reading a request.
379              
380              
381             =head1 SEE ALSO
382              
383             L,
384             L,
385             L,
386             L,
387             L
388              
389             =head1 BUGS
390              
391             There are two bugs lurking in NetServer::Generic. Or maybe they're
392             design flaws. I don't have time to fix them right now, but maybe
393             you'd like to contribute an hour or two and get your name in the
394             credits?
395              
396             Bug the first:
397              
398             NetServer::Generic attempts to make it easy to write a server by letting
399             the programmer concentrate on reading from STDIN and writing to STDOUT.
400             However, this form of i/o is line oriented. NetServer::Generic relies
401             on the buffering and i/o capabilities provided by Perl and IO::Socket
402             respectively. It doesn't buffer its own input.
403              
404             This means that in principle a malicious attacker (or just a badly-
405             written client program) can write a stream of bytes to a
406             NetServer::Generic application and, as long as those bytes don't
407             include a "\n", Perl will keep gobbling it up until it runs out of
408             virtual memory.
409              
410             This can be fixed by replacing the globbed IO::Socket::INET that is
411             attached to STDIN with something else -- probably an object that presents
412             itself as an IO::Stringy but that does its own buffering, so that it
413             will return I a line, or some sort of error message in $! if
414             it sees something undigestible in its input stream. (If anyone wants
415             to contribute a patch that fixes this, please feel free; this is an open
416             source project, after all ...)
417              
418             Bug the second:
419              
420             The select-based server was originally written because I wanted to
421             share state information between some forking servers and I couldn't
422             use System V shared memory (the application had to be portable to a
423             flavour of UNIX that didn't support it).
424              
425             It works okay, up to a point, but under heavy load on Linux it can run
426             into major problems. Partly this may be attributable to deficiencies
427             in the way Linux handles the select() system call (or so Stephen
428             Tweedie keeps telling me), but the result is that the select-based
429             server tends to drop some connections when it's under stress: if
430             two connections come in while it's serving another, the first may
431             never get processed before a timeout occurs.
432              
433             A somewhat worse problem is that IO::Select doesn't do buffered (line-
434             oriented) input; it just checks to see if one or more bytes are
435             waiting to be read from one of the file handles it's got hold of. It
436             is possible for a couple of bytes to come in (but not a whole line),
437             so that the select-based server merrily tries to process a transaction
438             and blocks until the rest of the input arrives -- thus ensuring that
439             the server is bottlenecked by the speed of the slowest client connection.
440              
441             Suggestion: if you need to serve lots of connections using select(),
442             look at the eventserver module instead. If you're a bit more
443             ambitious, the defect in NetServer::Generic is fixable by writing a
444             module with a similar API to IO::Select, but which provides buffering
445             for the file handles under its control and which only returns
446             something in response to can_read() when one of the buffers has a
447             complete line of input waiting.
448              
449             =head1 AUTHOR
450              
451             Charlie Stross (charle@antipope.org). With thanks for bugfixes and
452             patches to Marius Kjeldahl I, Art Sackett
453             I, Claudio Garcia I,
454             Claudio Calvelli I, Martin Waite
455             I. Debian package
456             contributed by Jon Middleton, I.
457              
458             =head1 HISTORY
459              
460             =over 4
461              
462             =item Version 0.1
463              
464             Based on the simple forking server in Chapter 10 of "Advanced Perl
465             Programming" by Sriram Srinivasan, with a modular wrapper to make
466             it easy to use and configure, and a rudimentary access control system.
467              
468             =item Version 0.2
469              
470             Added the B method to provide peer information.
471              
472             Bugfix to B from Marius Kjeldahl I.
473              
474             Added select-based server code, B method to switch between forking
475             and selection server modes.
476              
477             Updated test code (should do something now!)
478              
479             Added example: fortune server and client code.
480              
481             Supports NetServer::SMTP (and, internally, NetServer::vTID).
482              
483             =item Version 0.3
484              
485             fixed test failure.
486              
487             =item Version 1.0
488              
489             Added alpha-ish prefork server mode.
490              
491             Added alpha-ish multithreaded mode (UNSTABLE)
492              
493             Modified IP address filtering to cope with regexps
494             (suggested by Art Sackett I)
495              
496             Modified select() server to do non-blocking writes via a
497              
498             Non-blocking-socket class tied to STDIN/STDOUT
499              
500             Option to log new connection peer addresses via STDERR
501              
502             Extra test scripts
503              
504             Updated documentation
505              
506             =item 1.01
507              
508             Fix so it works on installations with no threading support (duh). Tested
509             on Solaris, too.
510              
511             =item 1.02
512              
513             Bugfixes to the preforked mode (thanks to Art Sackett for detecting
514             them). Bugfix to ok_to_serve() (thanks to Claudio Garcia,
515             cgarcia@dbitech.com). Some notes on the two known bugs (related
516             to buffering).
517              
518             =item 1.03
519              
520             Signal handling code was fixed to avoid leaving zombie processes
521             (thanks to Luis Munoz, lem@cantv.net)
522              
523             =back
524              
525              
526             =cut
527              
528             # NetServer::FieldTypes contains a hash of autoload method names, and the
529             # type of parameter they expect. For example, NetServer->callback() takes
530             # a coderef as a parameter; AUTOLOAD needs to know this so it can whine
531             # about incorrect parameter types.
532              
533             $NetServer::FieldTypes = {
534             "port" => "scalar",
535             "callback" => "code",
536             "listen" => "scalar",
537             "proto" => "scalar",
538             "hostname" => "scalar",
539             "timeout" => "scalar",
540             "root_pid" => "scalar",
541             "allowed" => "array",
542             "forbidden" => "array",
543             "peer" => "array",
544             "mode" => "scalar",
545             "trigger" => "code",
546             "sock" => "IO::Socket::INET",
547             "tags" => "hash",
548             "my_age" => "scalar",
549             "start_servers" => "scalar",
550             "min_spare_servers" => "scalar",
551             "max_servers" => "scalar",
552             "server_lifespan" => "scalar",
553             "fifo" => "scalar",
554             "read_pipe" => "scalar",
555             "write_pipe" => "scalar",
556             "handle" => "IO::File",
557             "scoreboard" => "hash",
558             "servername" => "array",
559             "parent_callback" => "code",
560             "ante_parent_callback" => "code",
561             };
562              
563             # $NetServer::Debug; if non-zero, emit some debugging info on STDERR
564              
565             $NetServer::Debug = 0;
566              
567             # here is a default callback routine. It basically echoes back anything
568             # you sent to the server, unless the line begins with quit, bye, or
569             # exit -- in which case it kills the server (rather than simply exiting).
570              
571             $NetServer::default_cb = sub {
572             my ($s) = shift;
573             my ($tmp) = "";
574             print STDOUT "Echo server: type bye to quit, ",
575             "exit to kill the server.\n\n" ;
576             while (defined ($tmp = )) {
577             return if ($tmp =~ /^bye/i);
578             $s->quit() if ($tmp =~ /^exit/i);
579             print STDOUT "You said:>$tmp\n";
580             }
581             };
582             # Methods
583              
584             sub new {
585 28 50   28 0 259 $NetServer::Debug && print STDERR "[", join("][", @_), "]\n";
586 28 50       378 my ($class) = shift if @_;
587 28         1066 my ($self) = {"listen" => 5,
588             "timeout" => 60,
589             "hostname" => "localhost",
590             "proto" => "tcp",
591             "callback" => $NetServer::default_cb,
592             "version" => $NetServer::Generic::VERSION,
593             };
594 28         226 $self->{tags} = $NetServer::FieldTypes;
595 28   50     341 bless $self, ($class or "Server");
596 28 50       180 if (@_) {
597 0         0 my (%tmp) = @_; my ($field) = "";
  0         0  
598 0         0 foreach $field (keys %tmp) {
599 0         0 $self->$field($tmp{$field});
600             }
601             }
602 28         299 return $self;
603             }
604              
605             sub VERSION {
606 0     0 0 0 my $self = shift;
607 0         0 return $self->{version};
608             }
609              
610             sub run_prefork {
611 2     2 0 6 my $self = shift;
612             # get preforking parameters or adopt sensible default values
613 2   50     16 my $start_servers = ($self->start_servers() or 5 );
614 2   50     8 my $spare_servers = ($self->min_spare_servers() or 1 );
615 2   50     22 my $max_servers = ($self->max_servers() or 10 );
616 2   50     18 my $server_lifespan = ($self->server_lifespan() or 1000 );
617              
618             # Create socket and bind, then Fork repeatedly up to $start_servers times.
619             # Once in each child, do a select-based loop. i.e. run_select, but exit
620             # after handling $server_lifespan transactions.
621             # Every time we do a task we write our PID and generation number down a
622             # pipe to the parent process, with a message when we exit.
623             #
624             # In the parent, keep track of how many servers are in use
625             # and fire up extra children (up to $max_servers) if the number in
626             # use leaves less than $spare_servers free.
627 2         8 my %init = (
628             LocalPort => $self->port(),
629             Listen => $self->listen(),
630             Proto => $self->proto(),
631             Reuse => 1
632             );
633 2 50       10 if ($self->hostname() ne "") {
634 2         8 $init{LocalAddr} = $self->hostname();
635             }
636 2         102 my ($main_sock) = new IO::Socket::INET(%init);
637 2 50       3070 if (! $main_sock) {
638 0         0 print STDERR "$$:run_select(): could not create socket: $!\n";
639 0         0 exit 0;
640             }
641 2         20 $self->sock($main_sock);
642 2 50       8 $NetServer::Debug && print STDERR
643             "Created socket(port => ", $self->port(), "\n",
644             " " x 15, "hostname => ", $self->hostname(), ")\n";
645 2         18 my $scoreboard = {};
646 2         34 $self->scoreboard($scoreboard);
647             # set up named pipe -- children will write, parent will read
648             #my $fifo = $self->_new_fifo();
649             #$self->fifo($fifo);
650             # switch to using a pipe instead
651 2         26 pipe(READ_PIPE, WRITE_PIPE);
652 2         12 $self->{read_pipe} = *READ_PIPE;
653 2         14 $self->{write_pipe} = *WRITE_PIPE;
654 2         20 $self->root_pid($$); # set server root PID
655             # now create lots of spawn
656 2         22 for (my $i = 0; $i < $start_servers; $i++) {
657 3         4267 my $pid = fork();
658 3 50       278 die "Cannot fork: $!\n" unless defined ($pid);
659 3 100       107 if ($pid == 0) {
660             # child
661 2         271 $self->_do_preforked_child();
662 0 0       0 $NetServer::Debug && print STDERR "$0:$$: end of transaction\n";
663 0         0 exit 0;
664             } else {
665             # parent
666 1         60 $scoreboard->{$pid} = "idle";
667 1 50       17 $NetServer::Debug && print STDERR "$0:$$: forked $pid\n";
668             }
669             }
670             # we have no forked $start_servers children that are
671             # in _do_preforked_child().
672 0         0 $self->scoreboard($scoreboard);
673 0         0 $self->_do_preforked_parent();
674 0         0 return;
675             }
676              
677             sub reap_child {
678 2     2 0 114 do {} while waitpid(-1, WNOHANG) > 0;
679             }
680              
681             sub _do_preforked_parent {
682 0     0   0 my $self = shift;
683             # we are a parent process to a bunch of raucous kiddies. We have an
684             # IO::Pipe called $self->reader() that we read status from and stick
685             # in a scoreboard. As processes die, we replace them. As the scoreboard
686             # fills up, we add extra servers. NB: when we fork, we replicate
687             # self->reader() and self->writer().
688              
689 0         0 my $n = "_do_preforked_adult($$)"; # for reporting status
690 0   0     0 my $start_servers = ( $self->start_servers() or 5 );
691 0   0     0 my $spare_servers = ( $self->min_spare_servers() or 1 );
692 0   0     0 my $max_servers = ( $self->max_servers() or 10 );
693 0   0     0 my $scoreboard = ( $self->scoreboard() or {} );
694 0         0 $SIG{CHLD} = \&reap_child;
695 0         0 my @buffer = ();
696 0         0 my $buffer = "";
697 0 0       0 $NetServer::Debug && print STDERR "$n: About to loop on scoreboard file\n";
698 0         0 my $loopcnt = 0;
699 0         0 my $busycnt = 0;
700 0         0 my @busyvec = ();
701             #while(@buffer = $self->_read_fifo()) {
702 0         0 *READ_PIPE = $self->read_pipe();
703 0         0 while($buffer = ) {
704 0 0       0 $NetServer::Debug
705             && print STDERR "busyvec: [", join("][", @busyvec), "]\n";
706 0         0 $loopcnt++;
707 0 0       0 $NetServer::Debug
708             && print STDERR "$n: in pipe read loop $loopcnt\n";
709 0         0 $buffer =~ tr/ //;
710 0         0 chomp $buffer;
711 0 0       0 $NetServer::Debug
712             && print STDERR "$n: buffer: $buffer\n";
713 0         0 my ($child_pid, $status) = split(/:/, $buffer);
714             # kids write $$:busy or $$:idle into the pipe whenever
715             # they change state.
716 0 0       0 if ($status eq "exit") {
    0          
    0          
    0          
717             # a child just exited on us
718 0 0       0 $NetServer::Debug
719             && print STDERR "$n: child $child_pid just died\n";
720 0         0 delete($scoreboard->{$child_pid});
721             } elsif ($status eq "busy") {
722 0         0 $scoreboard->{$child_pid} = "busy";
723 0         0 push(@busyvec, $child_pid);
724 0         0 $busycnt++;
725             } elsif ($status eq "idle") {
726 0         0 $scoreboard->{$child_pid} = "idle";
727 0         0 @busyvec = grep(!/$child_pid/, @busyvec);
728 0         0 $busycnt--;
729             } elsif ($status eq "start") {
730 0         0 $scoreboard->{$child_pid} = "idle";
731             }
732             $NetServer::Debug && print STDERR "$n: $child_pid has status [",
733 0 0       0 $scoreboard->{$child_pid}, "]\n",
734             "$n: got ", scalar(@busyvec), " busy kids\n";
735 0         0 $busycnt = scalar(@busyvec);
736 0         0 my $all_kids = scalar keys %$scoreboard;
737 0 0       0 $NetServer::Debug &&
738             print STDERR "$n: $busycnt children busy of $all_kids total\n";
739             # busy_kids is number of kids currently busy; all_kids is number of kids
740 0 0 0     0 if ((($all_kids - $busycnt) < $spare_servers) and
741             ($all_kids <= $max_servers)) {
742 0         0 my $kids_to_launch = ($spare_servers - ($all_kids - $busycnt)) +1;
743 0 0       0 $NetServer::Debug &&
744             print STDERR "spare servers: $spare_servers, ",
745             "all kids: $all_kids, ",
746             "busycnt: $busycnt\n",
747             "kids to launch = spares - (all - busy) +1 ",
748             " => $kids_to_launch\n";
749            
750             # launch new children
751 0         0 for (my ($i) = 0; $i < $kids_to_launch; $i++) {
752 0         0 my $pid = fork();
753 0 0       0 if ($pid == 0) {
754             # new child
755 0 0       0 $NetServer::Debug &&
756             print STDERR "spawned child\n";
757 0         0 $self->_do_preforked_child();
758 0         0 exit 0;
759             } else {
760             # parent
761 0 0       0 $NetServer::Debug && print STDERR
762             "$n: spawned new child $pid\n";
763 0         0 $scoreboard->{$pid} = "idle";
764             }
765             }
766             } # end of child launch cycle
767             $NetServer::Debug
768 0 0       0 && print STDERR "$n: scoreboard: \n", Dumper $scoreboard;
769             }
770 0         0 print STDERR "exited getline loop\n";
771             }
772              
773             sub _do_preforked_child {
774 2     2   42 my $self = shift;
775             # we are a preforked child process. We have an IO::Pipe called
776             # $self->writer() that we write strange things to. Each "strange thing"
777             # consists of a line containing our PID, a colon, and one of three strings:
778             # busy, idle, or exit. We run like a run_select server, except that we
779             # write a busy line whenever we accept a connection, an idle line whenever
780             # we finish handling a connection, and an exit line when our age exceeds
781             # $self->server_lifespan() and we suicide.
782             #
783 2         144 my $n = "_do_preforked_child($$)"; # for reporting status
784 2   50     351 my $server_lifespan = ( $self->server_lifespan() or 1000 );
785 2   50     154 my $my_age = ( $self->my_age() or 0 );
786 2         27 my $main_sock = $self->sock();
787 2         17 my $LOCK_SH = 1;
788 2         19 my $LOCK_EX = 2;
789 2         9 my $LOCK_NB = 4;
790 2         16 my $LOCK_UN = 8;
791 2         276 my $rh = new IO::Select($main_sock);
792 2 50       942 $NetServer::Debug && print STDERR "$n: Created IO::Select()\n";
793 2         96 *WRITE_PIPE = $self->{write_pipe};
794 2 50       17 $NetServer::Debug
795             && print WRITE_PIPE "$$:start\n";
796 2         31 my (@ready, @err) = ();
797 2 50       30 $NetServer::Debug
798             && print STDERR "$n: about to call IO::Select->can_read()\n";
799             SELECT:
800 2   33     140 while (@ready = $rh->can_read() or @err = $rh->has_error(0)) {
801 8 50       6376 if (scalar(@err) > 0) {
802 0         0 foreach my $s (@err) {
803 0 0       0 if ($NetServer::Debug > 0) {
804 0         0 print STDERR "Sock err: ", $s->error(), "\n";
805             }
806 0 0       0 if ($s->eof()) {
807 0         0 $rh->remove($s);
808 0         0 $s->close();
809             } else {
810 0         0 $s->clearerr();
811             }
812             }
813 0         0 @err = ();
814 0         0 next SELECT;
815             }
816 8 50       55 $NetServer::Debug && print STDERR "$n: got a connection\n";
817 8         36 foreach my $sock (@ready) {
818 9 50       26 $NetServer::Debug && print STDERR "$n: got a socket\n";
819 9 100       48 if ($sock == $main_sock) {
820 5 50       98 flock($sock, $LOCK_EX) or do {
821 0         0 print STDERR "+++ flock LOCK_EX failed on parent socket: ",
822             "$!\n";
823             };
824 5         256 my ($new_sock) = $sock->accept();
825 5         1968 flock $sock, $LOCK_UN;
826 5         23 $new_sock->autoflush(1);
827 5         193 $rh->add($new_sock);
828 5 50       248 if (! $self->ok_to_serve($new_sock)) {
829 0         0 $rh->remove($sock);
830 0         0 close($sock);
831             }
832             } else {
833 4 50       127 if (! eof($sock)) {
834 4         14 $my_age++;
835 4 50       20 $NetServer::Debug
836             && print STDERR "$n: print WRITE_PIPE ($$:busy)\n";
837 4         86 print WRITE_PIPE "$$:busy\n";
838 4 50       18 $NetServer::Debug
839             && print STDERR "$n: serving connection\n";
840 4         24 $sock->autoflush(1);
841 4         234 my ($in_port, $in_addr) = sockaddr_in($sock->sockname());
842 4         169 $self->servername([$in_port, $in_addr]);
843 4         30 my ($code) = $self->callback();
844 4         39 $self->sock($sock);
845 4         93 *OLD_STDIN = *STDIN;
846 4         35 *OLD_STDOUT = *STDOUT;
847 4         12 *STDIN = $sock;
848 4         13 *STDOUT = $sock;
849 4         13 select STDIN; $| = 1;
  4         51  
850 4         194 select STDOUT; $| = 1;
  4         11  
851 4         265 &$code($self);
852 3         30 *STDIN = *OLD_STDIN;
853 3         16 *STDOUT = *OLD_STDOUT;
854 3 50       19 $NetServer::Debug && do {
855 0         0 print STDERR "$n: print WRITE_PIPE $$:idle\n",
856             "$n: served $my_age calls\n";
857             };
858 3         38 print WRITE_PIPE "$$:idle\n$$:idle\n";
859 3         33 $rh->remove($sock);
860 3         562 close $sock;
861             } else {
862 0         0 $rh->remove($sock);
863 0         0 close($sock);
864             }
865             }
866             }
867 7 50       28 $NetServer::Debug && print STDERR "$n: checking age $my_age ",
868             "against lifespan $server_lifespan\n";
869 7 100       58 if ($my_age >= $server_lifespan) {
870 1 50       6 $NetServer::Debug
871             && print STDERR "$n: time to live exceeded\n",
872             "$n: print WRITE_PIPE $$:exit\n";
873             #$self->_write_fifo("$$:exit\n");
874 1         16 print WRITE_PIPE "$$:exit\n";
875 1         446 exit 0;
876             }
877             }
878             $NetServer::Debug
879 0 0       0 && print STDERR "Warning! Should never reach this point:",
880             join("\n", caller()), "\n";
881 0         0 print WRITE_PIPE "$$:exit\n";
882 0         0 exit 0;
883             }
884              
885              
886             sub run_select {
887 0     0 0 0 my $self = shift;
888 0         0 my ($main_sock) =
889             new IO::Socket::INET( # LocalAddr => $self->hostname(),
890             LocalPort => $self->port(),
891             Listen => $self->listen(),
892             Proto => $self->proto(),
893             Reuse => 1
894             );
895             # die "$$:run_select(): could not create socket: $!\n" unless ($main_sock);
896 0 0       0 if (! $main_sock) {
897 0         0 print STDERR "$$:run_select(): could not create socket: $!\n";
898 0         0 exit 0;
899             }
900 0 0       0 $NetServer::Debug && print STDERR "Created socket\n";
901 0         0 my $rh = new IO::Select($main_sock);
902 0 0       0 $NetServer::Debug && print STDERR "Created IO::Select()\n";
903 0         0 my (@ready) = ();
904 0         0 while (@ready = $rh->can_read() ) {
905 0 0       0 $NetServer::Debug && print STDERR
906             "NetServer::Generic::run_select(): got ",
907             scalar(@ready), " handles at ",
908             scalar(localtime(time)), "\n";
909 0         0 my ($sock) = "";
910 0         0 foreach $sock (@ready) {
911 0 0       0 if ($sock == $main_sock) {
912 0         0 my ($new_sock) = $sock->accept();
913 0         0 $new_sock->autoflush(1);
914 0         0 $rh->add($new_sock);
915 0 0       0 if (! $self->ok_to_serve($new_sock)) {
916 0         0 $rh->remove($sock);
917 0         0 close($sock);
918             }
919             } else {
920 0 0       0 if (! eof($sock)) {
921 0         0 $sock->autoflush(1);
922 0         0 my ($code) = $self->callback();
923 0         0 $self->sock($sock);
924 0         0 *STDIN = $sock;
925 0         0 *STDOUT = $sock;
926 0         0 select STDIN; $| = 1;
  0         0  
927 0         0 select STDOUT; $| = 1;
  0         0  
928 0         0 &$code($self);
929 0         0 $rh->remove($sock);
930 0         0 close $sock;
931             # shutdown($sock, 2);
932             } else {
933 0         0 $rh->remove($sock);
934 0         0 close($sock);
935             }
936             }
937             }
938             }
939             }
940              
941             sub run_thread {
942             # first pass at multithreaded execution -- as for fork() except we use
943             # threads. This is ugly -- may want to bodge it up to see if the
944             # run_select_fast method is a better model?
945 0     0 0 0 my ($self) = shift ;
946 0 0       0 if ($MAIN::no_thread == 1) {
947 0         0 warn "Warning: Threading not supported!\n";
948 0         0 return;
949             }
950 0         0 my %init = (
951             LocalPort => $self->port(),
952             Listen => $self->listen(),
953             Proto => $self->proto(),
954             Reuse => 1
955             );
956 0 0       0 if ($self->hostname() ne "") {
957 0         0 $init{LocalAddr} = $self->hostname();
958             }
959 0         0 my ($main_sock) = new IO::Socket::INET(%init);
960            
961 0 0       0 die "Socket could not be created: $!\n" unless ($main_sock);
962              
963             # we need to trap SIGKILL and SIGINT. If no traps are already
964             # defined by the user, add some default ones.
965 0 0       0 if (! exists $SIG{INT}) {
966             $SIG{INT} = sub {
967 0     0   0 print STDERR "\nSIGINT: server $$ ",
968             "shutting down \n";
969 0         0 exit 0;
970 0         0 };
971             }
972             # and make sure we wait() on children
973              
974             # now loop, forking whenever a new connection arrives on the listener
975              
976 0 0       0 $NetServer::Debug && print STDERR "Created socket\n";
977 0         0 my $rh = new IO::Select($main_sock);
978 0 0       0 $NetServer::Debug && print STDERR "Created IO::Select()\n";
979 0         0 my (@ready) = ();
980 0         0 while (@ready = $rh->can_read()) {
981 0 0       0 $NetServer::Debug && print STDERR
982             "NetServer::Generic::run_select(): got ",
983             scalar(@ready), " handles at ", scalar(localtime(time)), "\n";
984 0         0 my ($sock) = "";
985 0         0 foreach $sock (@ready) {
986 0 0       0 if ($sock == $main_sock) {
987 0         0 my ($new_sock) = $sock->accept();
988 0         0 $new_sock->autoflush(1);
989 0         0 $rh->add($new_sock);
990 0 0       0 if (! $self->ok_to_serve($new_sock)) {
991 0         0 $rh->remove($sock);
992 0         0 close($sock);
993             }
994             } else {
995 0 0       0 if (! eof($sock)) {
996 0         0 $sock->autoflush(1);
997 0         0 my ($code) = $self->callback();
998 0         0 $self->sock($sock);
999 0         0 *STDIN = $sock;
1000 0         0 *STDOUT = $sock;
1001 0         0 select STDIN; $| = 1;
  0         0  
1002 0         0 select STDOUT; $| = 1;
  0         0  
1003 0         0 my $t = new Thread &$code($self) ;
1004 0         0 $t->detach();
1005             #&$code($self);
1006 0         0 $rh->remove($sock);
1007 0         0 close $sock;
1008             # shutdown($sock, 2);
1009             } else {
1010 0         0 $rh->remove($sock);
1011 0         0 close($sock);
1012             }
1013             }
1014             }
1015             }
1016             }
1017              
1018             sub _thread {
1019             # handle socket setup inside a thread
1020             # args: IO::Socket::INET object, NetServer::Generic object
1021 0     0   0 my $sock = shift;
1022 0         0 my $self = shift;
1023 0   0     0 print STDERR "self is a ", (ref($self) or " kangaroo "), "\n";
1024 0 0       0 if ($self->ok_to_serve($sock)) {
1025 0         0 $sock->autoflush(1);
1026 0         0 my ($code) = $self->callback();
1027 0         0 *STDIN = $sock;
1028 0         0 *STDOUT = $sock;
1029 0         0 select STDIN; $| = 1;
  0         0  
1030 0         0 select STDOUT; $| = 1;
  0         0  
1031 0         0 $self->sock($sock);
1032 0         0 &$code($self);
1033             }
1034 0         0 shutdown($sock, 2);
1035 0         0 return;
1036             }
1037              
1038             sub run_fork {
1039 1     1 0 2 my ($self) = shift ;
1040 1         10 my %init = (
1041             LocalPort => $self->port(),
1042             Listen => $self->listen(),
1043             Proto => $self->proto(),
1044             Reuse => 1
1045             );
1046 1 50       10 if ($self->hostname() ne "") {
1047 1         3 $init{LocalAddr} = $self->hostname();
1048             }
1049 1         68 my ($main_sock) = new IO::Socket::INET(%init);
1050              
1051 1 50       381859 die "Socket could not be created: $!\n" unless ($main_sock);
1052              
1053              
1054             # we need to trap SIGKILL and SIGINT. If no traps are already
1055             # defined by the user, add some default ones.
1056 1 50       13 if (! exists $SIG{INT}) {
1057             $SIG{INT} = sub {
1058 0     0   0 print STDERR "\nSIGINT: server $$ ",
1059             "shutting down \n";
1060 0         0 exit 0;
1061 0         0 };
1062             }
1063             # and make sure we wait() on children
1064 1         28 $SIG{CHLD} = \&reap_child;
1065 1         47 my $parent_callback = $self->parent_callback();
1066 1         29 my $ante_fork_callback = $self->ante_fork_callback();
1067              
1068             # now loop, forking whenever a new connection arrives on the listener
1069 1         23 $self->root_pid($$); # set server root PID
1070 1         20 while (my ($new_sock) = $main_sock->accept()) {
1071 1 50       314 &$ante_fork_callback($self) if ( defined $ante_fork_callback );
1072 1         26 my $x_time = [ gettimeofday ]; # millisecond timer to track duration
1073 1         2434 my $pid = fork();
1074 1 50       88 die "Cannot fork: $!\n" unless defined ($pid);
1075 1 50       40 if ($pid == 0) {
1076             # child
1077 1 50       43 if ($NetServer::Debug != 0) {
1078 0         0 my ($peeraddr) = join(".", unpack("C4", $new_sock->peeraddr()));
1079 0         0 print STDERR "$$ : ", scalar(localtime(time)), " : ",
1080             "incoming connection from $peeraddr\n";
1081             }
1082 1 50       229 if ($self->ok_to_serve($new_sock)) {
1083 1 50       24 $NetServer::Debug
1084             && print STDERR $$, " : ", scalar(localtime(time)), " : ",
1085             "processing connection\n";
1086 1         28 $new_sock->autoflush(1);
1087 1         202 my ($code) = $self->callback();
1088 1         28 *STDIN = $new_sock;
1089 1         8 *STDOUT = $new_sock;
1090 1         6 select STDIN; $| = 1;
  1         4  
1091 1         6 select STDOUT; $| = 1;
  1         5  
1092 1         45 $self->sock($new_sock);
1093 1         32 &$code($self);
1094             } else {
1095 0 0       0 if ($NetServer::Debug) {
1096 0         0 print STDERR $$, " : ", scalar(localtime(time)), " : ",
1097             "rejecting unauthed connection\n";
1098             }
1099             }
1100 0 0       0 $NetServer::Debug && print STDERR "$0:$$: end of transaction\n";
1101 0         0 shutdown($new_sock, 2);
1102 0 0       0 $NetServer::Debug && print STDERR $$, " : ",
1103             scalar(localtime(time)), " : ",
1104             "took ", tv_interval($x_time),
1105             " seconds\n";
1106 0         0 exit 0;
1107             } else {
1108             # parent
1109 0 0       0 $NetServer::Debug && print STDERR "$0:$$: forked $pid\n";
1110 0 0       0 if ( defined $parent_callback ) {
1111 0         0 &$parent_callback($self);
1112             }
1113             }
1114             }
1115             }
1116              
1117             sub run_client {
1118 11     11 0 80 my ($self) = shift ;
1119 11         1698 $SIG{CHLD} = \&reap_child;
1120            
1121             # despatcher is a routine that dictates how often and how fast the
1122             # server forks and execs the test callback. The default sub (below)
1123             # returns immediately but is only true once, so the test is executed
1124             # immediately one time only. More realistic despatchers may sleep for
1125             # a random interval or even pre-fork themselves (for added chaos).
1126             my $despatcher = $self->trigger() ||
1127 0     0   0 sub { $NetServer::Generic::default_trigger++;
1128 0 0       0 return(($NetServer::Generic::default_trigger > 1) ? 0 : 1 );
1129 11   50     190 };
1130              
1131 11         142 my $code = $self->callback(); # sub to call in child process
1132 11         392 $self->root_pid($$); # set server root PID
1133 11         133 my $triggerval = &$despatcher;
1134 11   66     375 while (($triggerval ne "") && ($triggerval ne "0")) {
1135             # loop, forking to create new client sessions
1136 34         57494 my $pid = fork();
1137 34 50       1544 die "Cannot fork: $!\n" unless defined ($pid);
1138 34 100       2016 if ($pid == 0) {
1139             # child
1140 9 50       837 if ($NetServer::Debug != 0) {
1141 0         0 print STDERR "[$$] about to call new ",
1142             "IO::Socket::INET(\n\t\t\t\t",
1143             "PeerAddr => ", $self->hostname(),
1144             "\n\t\t\t\tPeerPort => ", $self->port(),
1145             "\n\t\t\t\tProto => ", $self->proto(),
1146             "\n)\n";
1147             }
1148 9         1844 my ($sock) =
1149             new IO::Socket::INET( PeerAddr => $self->hostname(),
1150             PeerPort => $self->port(),
1151             Proto => $self->proto(),
1152             );
1153 9 100       1515909 die "Socket could not be created: $!\n" unless ($sock);
1154 6         85 *STDIN = $sock;
1155 6         23 *STDOUT = $sock;
1156 6         30 select STDIN; $| = 1;
  6         28  
1157 6         83 select STDOUT; $| = 1;
  6         84  
1158 6         109 &$code($self, $triggerval);
1159 0         0 shutdown($sock, 2);
1160 0         0 exit 0;
1161             } else {
1162             # in parent
1163 25 50       267 $NetServer::Debug && print STDERR "$0:$$: forked $pid\n";
1164 25         1231 $triggerval = &$despatcher;
1165             }
1166             }
1167 2         2178791 wait; # for last child
1168 2         189 return;
1169             }
1170              
1171             sub run {
1172 14     14 0 79 my $self = shift;
1173 14 50       157 $NetServer::Debug && print STDERR "run() ...\n";
1174 14 100 66     173 if ( (! defined ($self->mode())) || (lc($self->mode()) eq "forking")) {
    50          
    50          
    100          
    50          
    50          
1175 1         16 $self->run_fork();
1176             } elsif ( lc($self->mode()) eq "select") {
1177 0         0 $self->run_select();
1178             } elsif ( lc($self->mode()) eq "select_fast") {
1179 0         0 $self->run_select_fast();
1180             } elsif ( lc($self->mode()) eq "client") {
1181 11         232 $self->run_client();
1182             } elsif ( lc($self->mode()) eq "threaded") {
1183 0         0 $self->run_thread();
1184             } elsif ( lc($self->mode()) eq "prefork") {
1185 2         16 $self->run_prefork();
1186             } else {
1187 0         0 my $aargh = "Unknown mode: " . $self->mode() . "\n";
1188 0         0 die $aargh;
1189             }
1190 2         67 return;
1191             }
1192              
1193             sub ok_to_serve($$) {
1194             # internal sub. Given a ref to a Server object, and an IO::Socket::INET,
1195             # see if we are allowed to serve the request. Return 1 if it's okay, 0
1196             # otherwise.
1197 6     6 0 41 my ($self, $new_sock) = @_;
1198 6         280 my ($junk, $peerp) = unpack_sockaddr_in($new_sock->peername());
1199 6         1853 my ($peername) = gethostbyaddr($peerp, AF_INET);
1200 6         141 my ($peeraddr) = join(".", unpack("C4", $new_sock->peeraddr()));
1201 6         810 $self->peer([ $peername, $peeraddr]);
1202             $NetServer::Debug &&
1203 6 50       39 print STDERR "$0:$$: request from ", join(" ", @{$self->peer()}), "\n";
  0         0  
1204 6 50 33     90 return 1 if ((! defined($self->forbidden())) &&
1205             (! defined($self->allowed())));
1206             # if we got here, forbidden or allowed are not undef,
1207             # so we have to do some checking
1208             # Now we have the originator's hostname and IP address, we check
1209             # them against the allowed list and the forbidden list.
1210 0         0 my ($found_allowed, $found_banned) = 0;
1211 0 0       0 if(defined ($self->allowed())) {
1212             ALLOWED:
1213 0         0 foreach (@{ $self->allowed() }) {
  0         0  
1214 0 0       0 next if (! defined($_));
1215 0 0 0     0 if (($peername =~ /^$_$/i) || ($peeraddr =~ /^$_$/i)) {
1216 0         0 $found_allowed++;
1217 0 0       0 $NetServer::Debug &&
1218             print STDERR "allowed: $_ matched $peername or $peeraddr\n";
1219 0         0 last ALLOWED;
1220             }
1221             }
1222             }
1223 0 0       0 if(defined ($self->forbidden())) {
1224             FORBIDDEN:
1225 0         0 foreach (@{ $self->forbidden() } ) {
  0         0  
1226 0 0       0 next if (! defined($_));
1227 0 0 0     0 if (($peername =~ /^$_$/i) || ($peeraddr =~ /^$_$/i)) {
1228 0         0 $found_banned++;
1229 0 0       0 $NetServer::Debug &&
1230             print STDERR "forbidden: $_ matched $peername ",
1231             "or $peeraddr\n";
1232 0         0 last FORBIDDEN;
1233             }
1234             }
1235             }
1236 0 0 0     0 ($found_banned && ! $found_allowed) && return 0;
1237 0 0 0     0 ($found_allowed && ! $found_banned) && return 1;
1238 0 0 0     0 ($found_allowed && $found_banned) && return 0;
1239 0         0 return 0;
1240             }
1241              
1242             #sub _new_fifo {
1243             # my $self = shift;
1244             # # create a new named pipe. Return its filename. This is used by
1245             # # the preforked server for children to send information back to their
1246             # # parent.
1247             # my $fname = "/tmp/fifo.$$";
1248             # my $mode = 666;
1249             # umask(0777); # possible security hole
1250             # mkfifo($fname, $mode) or die "Unable to mkfifo(): $!\n";
1251             # return $fname;
1252             #}
1253             #
1254             #sub _read_fifo { # Blocking read
1255             # my $self = shift;
1256             # # read a line from the designated fifo named $self->fifo()
1257             # my $handle = $self->fifo();
1258             # $SIG{ALRM} = sub { close FIFO };
1259             # open(FIFO, "<$handle") or die "Can't open $handle: $!\n";
1260             # alarm(1);
1261             # my @buffer = ();
1262             # alarm(0);
1263             # close FIFO;
1264             # return @buffer;
1265             #}
1266             #
1267             #sub _write_fifo { # Non-blocking write
1268             # my $self = shift;
1269             # my @args = @_;
1270             # my $handle = $self->fifo();
1271             # $SIG{ALRM} = sub { close FIFO };
1272             # open(FIFO, "+>$handle") or die "Can't open $handle: $!\n";
1273             # alarm(1);
1274             # print FIFO @_;
1275             # alarm(0);
1276             # close FIFO;
1277             # return;
1278             #}
1279              
1280             sub quit {
1281 2     2 1 15 my ($self) = shift;
1282 2 50       22 $NetServer::Debug && print STDERR "called shutdown(): root_pid is ",
1283             $self->root_pid(), "\n";
1284 2         37 kill 15, $self->root_pid();
1285 2         1366 exit;
1286             }
1287              
1288             sub AUTOLOAD {
1289 278     278   898 my ($self) = shift;
1290 278         842 my ($name) = $NetServer::Generic::AUTOLOAD;
1291 278         4069 $name =~ s/.*://;
1292 278 100       1276 if (@_) {
1293 108         999 my ($val) = shift;
1294             # rudimentary type checking
1295 108   100     1756 my ($r) = (ref($val) || "scalar");
1296 108 50       1107 if (! exists ($self->{tags}->{$name})) {
1297 0         0 warn "\tno such method: $name\n";
1298 0         0 return undef;
1299             }
1300 108 50       3243 if ($r !~ /$self->{tags}->{$name}/i) {
1301 0         0 warn "\t", ref($val), ": expecting a ", $self->{tags}->{$name}, "\n", "\tgot [", join("][", @_), "]\n";
1302 0         0 return undef;
1303             }
1304 108         1059 return $self->{$name} = $val;
1305             } else {
1306 170         5523 return $self->{$name};
1307             }
1308             }
1309              
1310              
1311             1;
1312