File Coverage

blib/lib/NetPacket/IPX.pm
Criterion Covered Total %
statement 51 51 100.0
branch 7 14 50.0
condition 3 9 33.3
subroutine 12 12 100.0
pod 3 4 75.0
total 76 90 84.4


line stmt bran cond sub pod time code
1 1     1   1517 use strict;
  1         3  
  1         44  
2 1     1   7 use warnings;
  1         2  
  1         51  
3              
4             package NetPacket::IPX;
5             BEGIN {
6 1     1   41 $NetPacket::IPX::AUTHORITY = 'cpan:YANICK';
7             }
8             # ABSTRACT: Assemble and disassemble IPX packets
9             $NetPacket::IPX::VERSION = '1.5.0';
10 1     1   1029 use parent qw(NetPacket);
  1         312  
  1         7  
11              
12 1     1   43 use Carp;
  1         2  
  1         924  
13              
14             sub new
15             {
16 1     1 1 5847 my ($class, %packet) = @_;
17            
18 1         5 foreach my $key(qw(tc type dest_network dest_node dest_socket
19             src_network src_node src_socket data))
20             {
21 9 50       24 croak("Missing $key argument") unless(defined($packet{$key}));
22             }
23            
24 1 50 33     18 croak("Invalid tc argument") unless($packet{tc} =~ m/^\d+$/ && $packet{tc} <= 255);
25 1 50 33     556 croak("Invalid type argument") unless($packet{type} =~ m/^\d+$/ && $packet{type} <= 255);
26            
27 1         7 _check_address("destination", $packet{dest_network}, $packet{dest_node}, $packet{dest_socket});
28 1         5 _check_address("source", $packet{src_network}, $packet{src_node}, $packet{src_socket});
29            
30 1         33 return bless(\%packet, $class);
31             }
32              
33             sub _check_address
34             {
35 2     2   5 my ($direction, $network, $node, $socket) = @_;
36            
37 2         10 my $OCTET = qr/[0-9A-F][0-9A-F]?/i;
38            
39 2 50       63 croak("Invalid $direction network") unless($network =~ m/^$OCTET(:$OCTET){3}$/);
40 2 50       45 croak("Invalid $direction node") unless($node =~ m/^$OCTET(:$OCTET){5}$/);
41 2 50 33     22 croak("Invalid $direction socket") unless($socket =~ m/^\d+$/ && $socket <= 65535);
42             }
43              
44             #
45             # Decode the packet
46             #
47              
48             sub decode
49             {
50 2     2 1 832 my ($class, $pkt, $parent) = @_;
51            
52 2         13 my $self = bless({
53             _parent => $parent,
54             _frame => $pkt,
55             }, $class);
56            
57 2 50       10 if(defined($pkt))
58             {
59             # Use array slices to capture the appropriate number of bytes
60             # from each address field.
61            
62             my (
63 2         5 $checksum, $length, $tc, $type,
64             @dst_network, @dst_node, $dst_socket,
65             @src_network, @src_node, $src_socket,
66             );
67            
68             (
69 2         48 $checksum, $length, $tc, $type,
70             @dst_network[0..3], @dst_node[0..5], $dst_socket,
71             @src_network[0..3], @src_node[0..5], $src_socket,
72             ) = unpack("nnCC C4C6n C4C6n", $pkt);
73            
74 2         13 $self->{tc} = $tc;
75 2         4 $self->{type} = $type;
76            
77 2         7 $self->{dest_network} = _addr_to_string(@dst_network);
78 2         7 $self->{dest_node} = _addr_to_string(@dst_node);
79 2         6 $self->{dest_socket} = $dst_socket;
80            
81 2         5 $self->{src_network} = _addr_to_string(@src_network);
82 2         8 $self->{src_node} = _addr_to_string(@src_node);
83 2         6 $self->{src_socket} = $src_socket;
84            
85 2         8 $self->{data} = substr($pkt, 30);
86             }
87            
88 2         10 return $self;
89             }
90              
91             #
92             # Strip header from packet and return the data contained in it
93             #
94              
95             sub strip {
96 1     1 0 687 my ($pkt) = @_;
97 1         5 return NetPacket::IPX->decode($pkt)->{data};
98             }
99              
100             #
101             # Encode a packet
102             #
103              
104             sub encode
105             {
106 1     1 1 1599 my ($self) = @_;
107            
108 1         15 return pack("nnCC", 0xFFFF, 30 + length($self->{data}), $self->{tc}, $self->{type})
109             ._addr_from_string($self->{dest_network})
110             ._addr_from_string($self->{dest_node})
111             .pack("n", $self->{dest_socket})
112             ._addr_from_string($self->{src_network})
113             ._addr_from_string($self->{src_node})
114             .pack("n", $self->{src_socket})
115             .$self->{data};
116             }
117              
118             sub _addr_to_string
119             {
120 8     8   17 my (@bytes) = @_;
121 8         11 return join(":", map { sprintf("%02X", $_) } @bytes);
  40         117  
122             }
123              
124             sub _addr_from_string
125             {
126 4     4   5 my ($string) = @_;
127 4         16 return join("", map { pack("C", hex($_)) } split(m/:/, $string));
  20         72  
128             }
129              
130             1;
131              
132             __END__