File Coverage

blib/lib/Net/Server/Proto/UDP.pm
Criterion Covered Total %
statement 51 60 85.0
branch 24 44 54.5
condition 4 12 33.3
subroutine 8 8 100.0
pod 2 6 33.3
total 89 130 68.4


line stmt bran cond sub pod time code
1             # -*- perl -*-
2             #
3             # Net::Server::Proto::UDP - Net::Server Protocol module
4             #
5             # Copyright (C) 2001-2022
6             #
7             # Paul Seamons
8             #
9             # Modified 2005 by Timothy Watt
10             # Added ability to deal with broadcast packets.
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::Proto::UDP;
22              
23 2     2   12 use strict;
  2         5  
  2         69  
24 2     2   11 use base qw(Net::Server::Proto::TCP);
  2         4  
  2         1869  
25              
26             my @udp_args = qw(
27             udp_recv_len
28             udp_recv_flags
29             udp_broadcast
30             );
31              
32 15     15 0 40 sub NS_proto { 'UDP' }
33 13 100   13 0 17 sub NS_recv_len { my $sock = shift; ${*$sock}{'NS_recv_len'} = shift if @_; return ${*$sock}{'NS_recv_len'} }
  13         23  
  10         16  
  13         17  
  13         26  
34 13 100   13 0 17 sub NS_recv_flags { my $sock = shift; ${*$sock}{'NS_recv_flags'} = shift if @_; return ${*$sock}{'NS_recv_flags'} }
  13         24  
  10         16  
  13         17  
  13         31  
35 13 100   13 0 19 sub NS_broadcast { my $sock = shift; ${*$sock}{'NS_broadcast'} = shift if @_; return ${*$sock}{'NS_broadcast'} }
  13         23  
  10         26  
  13         16  
  13         30  
36              
37             sub object {
38 10     10 1 19 my ($class, $info, $server) = @_;
39              
40             # we cannot do this at compile time because we have not yet read the configuration then
41             # (this is the height of rudeness changing another's class on their behalf)
42 10 50 33     36 $Net::Server::Proto::TCP::ISA[0] = Net::Server::Proto->ipv6_package($server)
43             if $Net::Server::Proto::TCP::ISA[0] eq 'IO::Socket::INET' && Net::Server::Proto->requires_ipv6($server);
44              
45 10   33     42 my $udp = $server->{'server'}->{'udp_args'} ||= do {
46 10         17 my %temp = map {$_ => undef} @udp_args;
  30         57  
47 10         18 $server->configure({map {$_ => \$temp{$_}} @udp_args});
  30         72  
48 10         30 \%temp;
49             };
50              
51             my $len = defined($info->{'udp_recv_len'}) ? $info->{'udp_recv_len'}
52 10 100       28 : defined($udp->{'udp_recv_len'}) ? $udp->{'udp_recv_len'}
    50          
53             : 4096;
54 10 50       49 $len = ($len =~ /^(\d+)$/) ? $1 : 4096;
55              
56             my $flg = defined($info->{'udp_recv_flags'}) ? $info->{'udp_recv_flags'}
57 10 50       24 : defined($udp->{'udp_recv_flags'}) ? $udp->{'udp_recv_flags'}
    50          
58             : 0;
59 10 50       31 $flg = ($flg =~ /^(\d+)$/) ? $1 : 0;
60              
61 10         38 my @sock = $class->SUPER::new(); # it is possible that multiple connections will be returned if INET6 is in effect
62 10         652 foreach my $sock (@sock) {
63 10         33 $sock->NS_host($info->{'host'});
64 10         26 $sock->NS_port($info->{'port'});
65 10         24 $sock->NS_ipv( $info->{'ipv'} );
66 10         23 $sock->NS_recv_len($len);
67 10         17 $sock->NS_recv_flags($flg);
68 10 50       45 $sock->NS_broadcast(exists($info->{'udp_broadcast'}) ? $info->{'udp_broadcast'} : $udp->{'upd_broadcast'});
69 10 50       25 ${*$sock}{'NS_orig_port'} = $info->{'orig_port'} if defined $info->{'orig_port'};
  0         0  
70             }
71 10 50       43 return wantarray ? @sock : $sock[0];
72             }
73              
74             sub connect {
75 1     1 1 2 my ($sock, $server) = @_;
76 1         2 my $host = $sock->NS_host;
77 1         2 my $port = $sock->NS_port;
78 1         2 my $ipv = $sock->NS_ipv;
79 1 50       3 my $isa_v6 = Net::Server::Proto->requires_ipv6($server) ? $sock->isa(Net::Server::Proto->ipv6_package($server)) : undef;
80              
81 1 50       13 $sock->SUPER::configure({
    0          
    0          
    50          
    50          
    50          
82             LocalPort => $port,
83             Proto => 'udp',
84             ReuseAddr => 1,
85             Reuse => 1, # may not be needed on UDP
86             (($host ne '*') ? (LocalAddr => $host) : ()), # * is all
87             ($isa_v6 ? (Domain => ($ipv eq '6') ? Socket6::AF_INET6() : ($ipv eq '4') ? Socket::AF_INET() : Socket::AF_UNSPEC()) : ()),
88             ($sock->NS_broadcast ? (Broadcast => 1) : ()),
89             }) or $server->fatal("Cannot bind to UDP port $port on $host [$!]");
90              
91 1 50 33     193 if ($port eq 0 and $port = $sock->sockport) {
    50 33        
92 0           $server->log(2, " Bound to auto-assigned port $port");
93 0           ${*$sock}{'NS_orig_port'} = $sock->NS_port;
  0            
94 0           $sock->NS_port($port);
95             } elsif ($port =~ /\D/ and $port = $sock->sockport) {
96 0           $server->log(2, " Bound to service port ".$sock->NS_port()."($port)");
97 0           ${*$sock}{'NS_orig_port'} = $sock->NS_port;
  0            
98 0           $sock->NS_port($port);
99             }
100             }
101              
102             1;
103              
104             __END__