File Coverage

blib/lib/Net/Server/Proto/TCP.pm
Criterion Covered Total %
statement 73 103 70.8
branch 29 62 46.7
condition 7 18 38.8
subroutine 15 18 83.3
pod 9 14 64.2
total 133 215 61.8


line stmt bran cond sub pod time code
1             # -*- perl -*-
2             #
3             # Net::Server::Proto::TCP - Net::Server Protocol module
4             #
5             # Copyright (C) 2001-2022
6             #
7             # Paul Seamons
8             #
9             # This package may be distributed under the terms of either the
10             # GNU General Public License
11             # or the
12             # Perl Artistic License
13             #
14             # All rights reserved.
15             #
16             ################################################################
17              
18             package Net::Server::Proto::TCP;
19              
20 12     12   70 use strict;
  12         18  
  12         495  
21 12     12   64 use warnings;
  12         20  
  12         952  
22 12     12   73 use IO::Socket::INET;
  12         22  
  12         763  
23 12     12   12772 use Net::Server::Proto;
  12         42  
  12         14452  
24              
25             our @ISA = qw(IO::Socket::INET); # we may dynamically change this to a v6 compatible class based upon our server configuration
26              
27 69     69 0 307 sub NS_proto { 'TCP' }
28 169 100   169 0 222 sub NS_port { my $sock = shift; ${*$sock}{'NS_port'} = shift if @_; return ${*$sock}{'NS_port'} }
  169         272  
  94         165  
  169         251  
  169         399  
29 151 100   151 0 553 sub NS_host { my $sock = shift; ${*$sock}{'NS_host'} = shift if @_; return ${*$sock}{'NS_host'} }
  151         281  
  85         168  
  151         180  
  151         317  
30 151 100   151 0 350 sub NS_ipv { my $sock = shift; ${*$sock}{'NS_ipv'} = shift if @_; return ${*$sock}{'NS_ipv'} }
  151         246  
  85         170  
  151         170  
  151         267  
31 92 100   92 0 108 sub NS_listen { my $sock = shift; ${*$sock}{'NS_listen'} = shift if @_; return ${*$sock}{'NS_listen'} }
  92         152  
  75         123  
  92         108  
  92         147  
32              
33             sub object {
34 75     75 1 134 my ($class, $info, $server) = @_;
35              
36             # we cannot do this at compile time because we have not yet read the configuration then
37 75 50 33     250 $ISA[0] = Net::Server::Proto->ipv6_package($server)
38             if $ISA[0] eq 'IO::Socket::INET' && Net::Server::Proto->requires_ipv6($server);
39              
40 75         380 my @sock = $class->SUPER::new();
41 75         6217 foreach my $sock (@sock) {
42 75         177 $sock->NS_host($info->{'host'});
43 75         165 $sock->NS_port($info->{'port'});
44 75         253 $sock->NS_ipv( $info->{'ipv'} );
45             $sock->NS_listen(defined($info->{'listen'}) ? $info->{'listen'}
46 75 100       276 : defined($server->{'server'}->{'listen'}) ? $server->{'server'}->{'listen'}
    100          
47             : Socket::SOMAXCONN());
48 75 50       174 ${*$sock}{'NS_orig_port'} = $info->{'orig_port'} if defined $info->{'orig_port'};
  0         0  
49             }
50 75 50       290 return wantarray ? @sock : $sock[0];
51             }
52              
53             sub log_connect {
54 15     15 1 34 my ($sock, $server) = @_;
55 15         33 $server->log(2, "Binding to ".$sock->NS_proto." port ".$sock->NS_port." on host ".$sock->NS_host." with IPv".$sock->NS_ipv);
56             }
57              
58             sub connect {
59 14     14 1 25 my ($sock, $server) = @_;
60 14         28 my $host = $sock->NS_host;
61 14         27 my $port = $sock->NS_port;
62 14         29 my $ipv = $sock->NS_ipv;
63 14         45 my $lstn = $sock->NS_listen;
64 14 50       71 my $isa_v6 = Net::Server::Proto->requires_ipv6($server) ? $sock->isa(Net::Server::Proto->ipv6_package($server)) : undef;
65              
66 14 50       508 $sock->SUPER::configure({
    0          
    0          
    50          
    50          
67             LocalPort => $port,
68             Proto => 'tcp',
69             Listen => $lstn,
70             ReuseAddr => 1,
71             Reuse => 1,
72             (($host ne '*') ? (LocalAddr => $host) : ()), # * is all
73             ($isa_v6 ? (Domain => ($ipv eq '6') ? Socket6::AF_INET6() : ($ipv eq '4') ? Socket::AF_INET() : Socket::AF_UNSPEC()) : ()),
74             }) || $server->fatal("Can't connect to TCP port $port on $host [$!]");
75              
76 14 50 33     4815 if ($port eq '0' and $port = $sock->sockport) {
    50 33        
77 0         0 $server->log(2, " Bound to auto-assigned port $port");
78 0         0 ${*$sock}{'NS_orig_port'} = $sock->NS_port;
  0         0  
79 0         0 $sock->NS_port($port);
80             } elsif ($port =~ /\D/ and $port = $sock->sockport) {
81 0         0 $server->log(2, " Bound to service port ".$sock->NS_port()."($port)");
82 0         0 ${*$sock}{'NS_orig_port'} = $sock->NS_port;
  0         0  
83 0         0 $sock->NS_port($port);
84             }
85             }
86              
87             sub reconnect { # after a sig HUP
88 0     0 1 0 my ($sock, $fd, $server, $port) = @_;
89 0         0 $server->log(3,"Reassociating file descriptor $fd with ".$sock->NS_proto." on [".$sock->NS_host."]:".$sock->NS_port.", using IPv".$sock->NS_ipv);
90 0 0       0 $sock->fdopen($fd, 'w') or $server->fatal("Error opening to file descriptor ($fd) [$!]");
91              
92 0 0       0 my $isa_v6 = Net::Server::Proto->requires_ipv6($server) ? $sock->isa(Net::Server::Proto->ipv6_package($server)) : undef;
93 0 0       0 if ($isa_v6) {
94 0         0 my $ipv = $sock->NS_ipv;
95 0 0       0 ${*$sock}{'io_socket_domain'} = ($ipv eq '6') ? Socket6::AF_INET6() : ($ipv eq '4') ? Socket::AF_INET() : Socket::AF_UNSPEC();
  0 0       0  
96             }
97              
98 0 0       0 if ($port ne $sock->NS_port) {
99 0         0 $server->log(2, " Re-bound to previously assigned port $port");
100 0         0 ${*$sock}{'NS_orig_port'} = $sock->NS_port;
  0         0  
101 0         0 $sock->NS_port($port);
102             }
103             }
104              
105             sub accept {
106 9     9 1 23 my ($sock, $class) = (@_);
107 9         14 my ($client, $peername);
108 9 50       22 if (wantarray) {
109 0         0 ($client, $peername) = $sock->SUPER::accept($class);
110             } else {
111 9         111 $client = $sock->SUPER::accept($class);
112             }
113 9 50       4503 if (defined $client) {
114 9         31 $client->NS_port($sock->NS_port);
115             }
116 9 50       105 return wantarray ? ($client, $peername) : $client;
117             }
118              
119             sub poll_cb { # implemented for psgi compatibility - TODO - should poll appropriately for Multipex
120 0     0 1 0 my ($self, $cb) = @_;
121 0         0 return $cb->($self);
122             }
123              
124             ###----------------------------------------------------------------###
125              
126             sub read_until { # only sips the data - but it allows for compatibility with SSLEAY
127 2     2 1 11 my ($client, $bytes, $end_qr) = @_;
128 2 0 33     8 die "One of bytes or end_qr should be defined for TCP read_until\n" if !defined($bytes) && !defined($end_qr);
129 2         3 my $content = '';
130 2         4 my $ok = 0;
131 2         3 while (1) {
132 109         250 $client->read($content, 1, length($content));
133 109 50 33     808 if (defined($bytes) && length($content) >= $bytes) {
    100 66        
134 0         0 $ok = 2;
135 0         0 last;
136             } elsif (defined($end_qr) && $content =~ $end_qr) {
137 2         4 $ok = 1;
138 2         5 last;
139             }
140             }
141 2 50       11 return wantarray ? ($ok, $content) : $content;
142             }
143              
144             ###----------------------------------------------------------------###
145              
146             ### a string containing any information necessary for restarting the server
147             ### via a -HUP signal
148             ### a newline is not allowed
149             ### the hup_string must be a unique identifier based on configuration info
150             sub hup_string {
151 30     30 1 4078 my $sock = shift;
152 30 50       47 return join "|", $sock->NS_host, $sock->NS_port, $sock->NS_proto, 'ipv'.$sock->NS_ipv, (defined(${*$sock}{'NS_orig_port'}) ? ${*$sock}{'NS_orig_port'} : ());
  30         138  
  0            
153             }
154              
155             sub show {
156 0     0 1   my $sock = shift;
157 0           return "Ref = \"".ref($sock). "\" (".$sock->hup_string.")\n";
158             }
159              
160             1;
161              
162             __END__