File Coverage

blib/lib/IO/Socket/Netlink/Generic.pm
Criterion Covered Total %
statement 52 65 80.0
branch 5 14 35.7
condition n/a
subroutine 17 19 89.4
pod 6 8 75.0
total 80 106 75.4


line stmt bran cond sub pod time code
1             # You may distribute under the terms of either the GNU General Public License
2             # or the Artistic License (the same terms as Perl itself)
3             #
4             # (C) Paul Evans, 2010-2011 -- leonerd@leonerd.org.uk
5              
6             package IO::Socket::Netlink::Generic;
7              
8 2     2   1868 use strict;
  2         30  
  2         71  
9 2     2   11 use warnings;
  2         4  
  2         62  
10 2     2   11 use base qw( IO::Socket::Netlink );
  2         3  
  2         920  
11              
12             our $VERSION = '0.04';
13              
14 2     2   11 use Carp;
  2         4  
  2         128  
15              
16 2         1259 use Socket::Netlink::Generic qw(
17             NETLINK_GENERIC
18             CTRL_CMD_GETFAMILY
19 2     2   19 );
  2         3  
20              
21             __PACKAGE__->register_protocol( NETLINK_GENERIC );
22              
23             =head1 NAME
24              
25             C - Object interface to C
26             netlink protocol sockets
27              
28             =head1 SYNOPSIS
29              
30             use IO::Socket::Netlink::Generic;
31              
32             my $genlsock = IO::Socket::Netlink::Generic->new or die "socket: $!";
33              
34             printf "TASKSTATS family ID is %d\n",
35             $genlsock->get_family_by_name( "TASKSTATS" )->{id};
36              
37             =head1 DESCRIPTION
38              
39             This subclass of L implements the C
40             protocol. It is itself intended to serve as a base class for particular
41             generic families to extend.
42              
43             =cut
44              
45             =head1 CLASS METHODS
46              
47             =head2 $class->register_family_name( $name )
48              
49             Must be called by a subclass implementing a particular protocol family, to
50             declare its family name. The first time a socket in that class is constructed,
51             this name will be looked up into an ID number.
52              
53             =cut
54              
55             my %pkg2familyname;
56             my %familyname2pkg;
57              
58             sub register_family_name
59             {
60 0     0 1 0 my ( $pkg, $family_name ) = @_;
61              
62 0         0 $pkg2familyname{$pkg} = $family_name;
63 0         0 $familyname2pkg{$family_name} = $pkg;
64             }
65              
66             sub new
67             {
68 1     1 1 17 my $class = shift;
69 1         15 $class->SUPER::new( Protocol => NETLINK_GENERIC, @_ );
70             }
71              
72             sub configure
73             {
74 1     1 0 138 my $self = shift;
75 1         3 my ( $arg ) = @_;
76              
77 1         9 my $ret = $self->SUPER::configure( $arg );
78              
79 1         3 my $class = ref $self;
80 1 50       5 if( $class ne __PACKAGE__ ) {
81 0 0       0 defined( my $family_name = $pkg2familyname{$class} ) or
82             croak "No family name defined for $class";
83              
84 0         0 my $family_id = $self->get_family_by_name( $family_name )->{id};
85 0         0 $class->message_class->register_nlmsg_type( $family_id );
86              
87 0         0 ${*$self}{default_nlmsg_type} = $family_id;
  0         0  
88             }
89              
90 1         6 return $ret;
91             }
92              
93             sub new_message
94             {
95 3     3 1 1516 my $self = shift;
96              
97 3         34 $self->SUPER::new_message(
98 3 50       6 ( defined ${*$self}{default_nlmsg_type} ? ( nlmsg_type => ${*$self}{default_nlmsg_type} ) : () ),
  0         0  
99             @_,
100             );
101             }
102              
103             sub new_command
104             {
105 0     0 1 0 my $self = shift;
106              
107 0         0 $self->SUPER::new_command(
108 0 0       0 ( defined ${*$self}{default_nlmsg_type} ? ( nlmsg_type => ${*$self}{default_nlmsg_type} ) : () ),
  0         0  
109             @_,
110             );
111             }
112              
113             sub message_class
114             {
115 5     5 0 43 return "IO::Socket::Netlink::Generic::_Message";
116             }
117              
118             =head1 METHODS
119              
120             =cut
121              
122             =head2 $family = $sock->get_family_by_name( $name )
123              
124             =cut
125              
126             sub get_family_by_name
127             {
128 1     1 1 2158 my $self = shift;
129 1         3 my ( $name ) = @_;
130              
131 1         4 return $self->_get_family( name => $name );
132             }
133              
134             =head2 $family = $sock->get_family_by_id( $id )
135              
136             =cut
137              
138             sub get_family_by_id
139             {
140 1     1 1 1990 my $self = shift;
141 1         3 my ( $id ) = @_;
142              
143 1         4 return $self->_get_family( id => $id );
144             }
145              
146             =pod
147              
148             Query the kernel for information on the C family specifed by
149             name or ID number, and return information about it. Returns a HASH reference
150             containing the following fields:
151              
152             =over 8
153              
154             =item id => NUMBER
155              
156             =item name => STRING
157              
158             =item version => NUMBER
159              
160             =item hdrsize => NUMBER
161              
162             =item maxattr => NUMBER
163              
164             =back
165              
166             =cut
167              
168             sub _get_family
169             {
170 2     2   5 my $self = shift;
171 2         7 my %searchattrs = @_;
172              
173 2 50       22 $self->send_nlmsg( $self->new_request(
174             nlmsg_type => NETLINK_GENERIC,
175              
176             cmd => CTRL_CMD_GETFAMILY,
177             nlattrs => \%searchattrs,
178             ) ) or croak "Cannot send - $!";
179              
180 2 50       172 $self->recv_nlmsg( my $message, 32768 ) or
181             croak "Cannot recv - $!";
182              
183 2 50       8 $message->nlmsg_type == NETLINK_GENERIC or
184             croak "Expected nlmsg_type == NETLINK_GENERIC";
185              
186 2         8 return $message->nlattrs;
187             }
188              
189             package IO::Socket::Netlink::Generic::_Message;
190              
191 2     2   10 use base qw( IO::Socket::Netlink::_Message );
  2         2  
  2         923  
192              
193 2     2   10 use Carp;
  2         3  
  2         102  
194              
195 2         892 use Socket::Netlink::Generic qw(
196             :DEFAULT
197             pack_genlmsghdr unpack_genlmsghdr
198 2     2   10 );
  2         37  
199              
200             =head1 MESSAGE OBJECTS
201              
202             Sockets in this class provide the following extra field accessors on their
203             message objects:
204              
205             =cut
206              
207             __PACKAGE__->is_subclassed_by_type;
208              
209             __PACKAGE__->register_nlmsg_type( NETLINK_GENERIC );
210              
211             =over 8
212              
213             =item * $message->cmd
214              
215             ID number of the command to give to the family
216              
217             =item * $message->version
218              
219             Version number of the interface
220              
221             =item * $message->genlmsg
222              
223             Accessor for the trailing data buffer; intended for subclasses to use
224              
225             =back
226              
227             =cut
228              
229             __PACKAGE__->is_header(
230             data => "nlmsg",
231             fields => [
232             [ cmd => 'decimal' ],
233             [ version => 'decimal' ],
234             [ genlmsg => 'bytes' ],
235             ],
236             pack => \&pack_genlmsghdr,
237             unpack => \&unpack_genlmsghdr,
238             );
239              
240             sub nlmsg_string
241             {
242 1     1   2 my $self = shift;
243 1         5 return sprintf "cmd=%d,version=%d,%s", $self->cmd, $self->version, $self->genlmsg_string;
244             }
245              
246             sub genlmsg_string
247             {
248 1     1   3 my $self = shift;
249 1         5 return sprintf "{%d bytes}", length $self->genlmsg;
250             }
251              
252             __PACKAGE__->has_nlattrs(
253             "genlmsg",
254             id => [ CTRL_ATTR_FAMILY_ID, "u16" ],
255             name => [ CTRL_ATTR_FAMILY_NAME, "asciiz" ],
256             version => [ CTRL_ATTR_VERSION, "u32" ],
257             hdrsize => [ CTRL_ATTR_HDRSIZE, "u32" ],
258             maxattr => [ CTRL_ATTR_MAXATTR, "u32" ],
259             );
260              
261             =head1 SEE ALSO
262              
263             =over 4
264              
265             =item *
266              
267             L - interface to Linux's C netlink
268             socket protocol
269              
270             =item *
271              
272             L - Object interface to C domain sockets
273              
274             =back
275              
276             =head1 AUTHOR
277              
278             Paul Evans
279              
280             =cut
281              
282             0x55AA;