File Coverage

blib/lib/Net/NBName.pm
Criterion Covered Total %
statement 18 116 15.5
branch 0 22 0.0
condition 0 10 0.0
subroutine 6 14 42.8
pod 3 3 100.0
total 27 165 16.3


line stmt bran cond sub pod time code
1 1     1   6681 use strict;
  1         3  
  1         57  
2 1     1   6 use warnings;
  1         3  
  1         53  
3            
4             package Net::NBName;
5            
6 1     1   1996 use Net::NBName::NodeStatus;
  1         3  
  1         38  
7 1     1   887 use Net::NBName::NameQuery;
  1         4  
  1         39  
8            
9 1     1   7 use vars '$VERSION';
  1         2  
  1         549  
10             $VERSION = "0.26";
11            
12             sub new
13             {
14 0     0 1   my $class = shift;
15            
16 0           my $self = {};
17 0           bless $self, $class;
18 0           return $self;
19             }
20            
21             sub node_status
22             {
23 0     0 1   my $self = shift;
24 0           my $host = shift;
25 0           my $timeout = shift;
26            
27 0           my $req = Net::NBName::Request->new;
28 0           $req->data(0, "*", "\x00", 0, 0x21);
29 0           my $resp = $req->unicast($host, $timeout);
30 0 0         if ($resp) {
31 0           my $ns = Net::NBName::NodeStatus->new($resp);
32 0           return $ns;
33             } else {
34 0           return undef;
35             }
36             }
37            
38             sub name_query
39             {
40 0     0 1   my $self = shift;
41 0           my $host = shift;
42 0           my $name = shift;
43 0           my $suffix = shift;
44 0   0       my $flags = shift || 0x0100;
45 0           my $timeout = shift;
46            
47 0           my $req = Net::NBName::Request->new;
48 0           $req->data($flags, $name, ' ', $suffix, 0x20);
49 0           my ($resp, $from_ip);
50 0 0         if (defined($host)) {
51 0           $resp = $req->unicast($host, $timeout);
52             } else {
53 0           ($resp, $from_ip) = $req->broadcast($timeout);
54             }
55            
56 0 0         if ($resp) {
57 0           my $nq = Net::NBName::NameQuery->new($resp);
58 0           return $nq;
59             } else {
60 0           return undef;
61             }
62             }
63            
64             package Net::NBName::Request;
65            
66 1     1   1303 use Socket;
  1         5136  
  1         1444  
67            
68             sub new
69             {
70 0     0     my $class = shift;
71            
72 0           my $self = {};
73 0           bless $self, $class;
74 0           return $self;
75             }
76            
77             sub data
78             {
79 0     0     my $self = shift;
80 0           my ($flags, $name, $pad, $suffix, $qtype) = @_;
81            
82 0           my $data = "";
83 0           $data .= pack("n*", $$, $flags, 1, 0, 0, 0);
84 0           $data .= _encode_name($name, $pad, $suffix);
85 0           $data .= pack("n*", $qtype, 0x0001);
86            
87 0           $self->{data} = $data;
88             }
89            
90             sub _encode_name
91             {
92 0     0     my $name = uc(shift);
93 0   0       my $pad = shift || "\x20";
94 0   0       my $suffix = shift || 0x00;
95            
96 0           $name .= $pad x (16-length($name));
97 0           substr($name, 15, 1) = chr($suffix & 0xFF);
98            
99 0           my $encoded_name = "";
100 0           for my $c (unpack("C16", $name)) {
101 0           $encoded_name .= chr(ord('A') + (($c & 0xF0) >> 4));
102 0           $encoded_name .= chr(ord('A') + ($c & 0xF));
103             }
104            
105             # Note that the _encode_name function doesn't add any scope,
106             # nor does it calculate the length (32), it just prefixes it
107 0           return "\x20" . $encoded_name . "\x00";
108             }
109            
110             sub unicast
111             {
112 0     0     my $self = shift;
113 0           my $host = shift;
114             # Timeout should be 250ms according to RFC1002
115 0   0       my $timeout = shift || 0.25;
116            
117 0           my $data = $self->{data};
118            
119 0           my $protocol = getprotobyname('udp');
120 0           my $port = 137;
121 0 0         socket(SOCK, AF_INET, SOCK_DGRAM, $protocol) or return undef;
122 0           my $to_saddr = sockaddr_in($port, inet_aton($host));
123            
124 0 0         send(SOCK, $data, 0, $to_saddr) or return undef;
125            
126 0           my $rin = "";
127 0           my $rout;
128 0           vec($rin, fileno(SOCK), 1) = 1;
129            
130 0           my ($nfound, $timeleft) = select($rout = $rin, undef, undef, $timeout);
131 0 0         if ($nfound) {
132 0           my $resp;
133 0 0         if (my $from_saddr = recv(SOCK, $resp, 2000, 0)) {
134 0           my ($from_port, $from_ip) = sockaddr_in($from_saddr);
135 0           close(SOCKET);
136 0           return $resp;
137             } else { # socket error
138             #printf "Errno %d %s\n", $!, $^E;
139 0           close(SOCKET);
140 0           return undef;
141             }
142             } else { # timed out
143 0           close(SOCKET);
144 0           return undef;
145             }
146             }
147            
148             sub broadcast
149             {
150 0     0     my $self = shift;
151             # Timeout should be 5s according to rfc1002 (but I've used 1s)
152 0   0       my $timeout = shift || 1;
153            
154 0           my $host = "255.255.255.255";
155 0           my $data = $self->{data};
156            
157 0           my $protocol = getprotobyname('udp');
158 0           my $port = 137;
159 0 0         socket(SOCK, AF_INET, SOCK_DGRAM, $protocol) or return undef;
160 0           setsockopt(SOCK, SOL_SOCKET, SO_BROADCAST, 1);
161            
162 0           my $to_saddr = sockaddr_in($port, inet_aton($host));
163            
164 0 0         send(SOCK, $data, 0, $to_saddr) or return undef;
165 0           my $rin = "";
166 0           my $rout;
167 0           vec($rin, fileno(SOCK), 1) = 1;
168            
169 0           my ($nfound, $timeleft) = select($rout = $rin, undef, undef, $timeout);
170 0 0         if ($nfound) {
171 0           my $resp;
172 0 0         if (my $from_saddr = recv(SOCK, $resp, 2000, 0)) {
173 0           my ($from_port, $from_ip) = sockaddr_in($from_saddr);
174 0           close(SOCKET);
175 0           return $resp, inet_ntoa($from_ip);
176             } else { # socket error
177             #printf "Errno %d %s\n", $!, $^E;
178 0           close(SOCKET);
179 0           return undef;
180             }
181             } else { # timed out
182 0           close(SOCKET);
183 0           return undef;
184             }
185             }
186            
187             1;
188            
189             __END__