File Coverage

blib/lib/IO/EventMux/Socket/MsgHdr.pm
Criterion Covered Total %
statement 61 89 68.5
branch 14 36 38.8
condition 2 20 10.0
subroutine 19 20 95.0
pod 10 10 100.0
total 106 175 60.5


line stmt bran cond sub pod time code
1             package IO::EventMux::Socket::MsgHdr;
2 3     3   127571 use strict;
  3         10  
  3         115  
3 3     3   16 use warnings;
  3         7  
  3         207  
4              
5             our $VERSION = '0.02';
6              
7             =head1 NAME
8              
9             IO::EventMux::Socket::MsgHdr - sendmsg, recvmsg and ancillary data operations
10              
11             =head1 SYNOPSIS
12              
13             use IO::EventMux::Socket::MsgHdr;
14             use Socket;
15              
16             # sendto() behavior
17             my $echo = sockaddr_in(7, inet_aton("10.20.30.40"));
18             my $outMsg = new IO::EventMux::Socket::MsgHdr(buf => "Testing echo service",
19             name => $echo);
20             sendmsg(OUT, $outMsg, 0) or die "sendmsg: $!\n";
21              
22             # recvfrom() behavior, OO-style
23             my $msgHdr = new IO::EventMux::Socket::MsgHdr(buflen => 512)
24              
25             $msgHdr->buflen(8192); # maybe 512 wasn't enough!
26             $msgHdr->namelen(256); # only 16 bytes needed for IPv4
27            
28             die "recvmsg: $!\n" unless defined recvmsg(IN, $msgHdr, 0);
29              
30             my ($port, $iaddr) = sockaddr_in($msgHdr->name());
31             my $dotted = inet_ntoa($iaddr);
32             print "$dotted:$port said: " . $msgHdr->buf() . "\n";
33              
34             # Pack ancillary data for sending
35             $outHdr->cmsghdr(SOL_SOCKET, # cmsg_level
36             SCM_RIGHTS, # cmsg_type
37             pack("i", fileno(STDIN))); # cmsg_data
38             sendmsg(OUT, $msgHdr);
39              
40             # Unpack the same
41             my $inHdr = IO::EventMux::Socket::MsgHdr->new(buflen => 8192, controllen => 256);
42             recvmsg(IN, $inHdr, $flags);
43             my ($level, $type, $data) = $inHdr->cmsghdr();
44             my $new_fileno = unpack('i', $data);
45             open(NewFH, '<&=' . $new_fileno); # voila!
46              
47             =head1 DESCRIPTION
48              
49             IO::EventMux::Socket::MsgHdr is a fork of L as the old author
50             did not respond in regards to a cleanup patch to get rid of warnings in both
51             modules and tests. This fork has since restructured the module so it's simpler
52             to understand and maintain.
53              
54             IO::EventMux::Socket::MsgHdr provides advanced socket messaging operations via
55             L and L. Like their C counterparts, these functions accept
56             few parameters, instead stuffing a lot of information into a complex structure.
57              
58             This structure describes the message sent or received (C), the peer on
59             the other end of the socket (L), and ancillary or so-called control
60             information (L). This ancillary data may be used for file descriptor
61             passing, IPv6 operations, and a host of implementation-specific extensions.
62              
63             =cut
64              
65             =head1 METHODS
66              
67             =over
68              
69             =cut
70              
71 3     3   91 use base "Exporter";
  3         12  
  3         503  
72              
73             our @EXPORT = qw(sendmsg recvmsg);
74             our @EXPORT_OK = qw(pack_cmsghdr unpack_cmsghdr socket_errors);
75              
76 3         673 use Errno qw(EPROTO ECONNREFUSED ETIMEDOUT EMSGSIZE ECONNREFUSED EHOSTUNREACH
77 3     3   17191 ENETUNREACH EACCES EAGAIN ENOTCONN ECONNRESET EWOULDBLOCK);
  3         19782  
78 3     3   28 use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK);
  3         4  
  3         182  
79 3     3   17267 use POSIX qw(strerror);
  3         38912  
  3         24  
80              
81 3     3   10474 use Socket;
  3         7  
  3         2295  
82             use constant {
83 3         9315 SOL_IP => 0,
84             IP_RECVERR => 11,
85             SO_EE_ORIGIN_NONE => 0,
86             SO_EE_ORIGIN_LOCAL => 1,
87             SO_EE_ORIGIN_ICMP => 2,
88             SO_EE_ORIGIN_ICMP6 => 3,
89 3     3   19 };
  3         5  
90              
91              
92             =item new()
93              
94             Return a new IO::EventMux::Socket::MsgHdr object. Optional PARAMETERS may specify method
95             names (C, C, C, C or their corresponding I<...len>
96             methods where applicable) and values, sparing an explicit call to those
97             methods.
98              
99             =cut
100              
101             sub new {
102 25     25 1 21448 my $class = shift;
103 25         98 my $self = { name => undef,
104             control => undef,
105             flags => 0 };
106            
107 25         70 bless $self, $class;
108              
109 25         75 my %args = @_;
110 25         69 foreach my $m (keys %args) {
111 35         124 $self->$m($args{$m});
112             }
113              
114 25         103 return $self;
115             }
116              
117              
118             =item name [SCALAR]
119              
120             Get or set the socket name (address) buffer, an attribute analogous to the
121             optional TO and FROM parameters of L and L.
122             Note that socket names are packed structures.
123              
124             =cut
125              
126             sub name {
127 19     19 1 59 my ($self, $var) = @_;
128 19 100       47 $self->{name} = $var if defined $var;
129 19         74 $self->{name};
130             }
131              
132             =item namelen LENGTH
133              
134             =cut
135              
136             sub namelen {
137 9     9 1 18 my ($self, $nlen) = @_;
138 9         24 $self->_set_length("name", $nlen);
139             }
140              
141             =item buf [SCALAR]
142              
143             =cut
144              
145             sub buf {
146 19     19 1 134 my ($self, $var) = @_;
147 19 100       65 $self->{buf} = $var if defined $var;
148 19         60 $self->{buf};
149             }
150              
151              
152             =item buflen LENGTH
153              
154             C gets the current message buffer or sets it to SCALAR. C
155             allocates LENGTH bytes for use in L.
156              
157             =cut
158              
159             sub buflen {
160 10     10 1 21 my ($self, $nlen) = @_;
161 10         25 $self->_set_length("buf",$nlen);
162             }
163              
164             =item control()
165              
166             =cut
167              
168             sub control {
169 5     5 1 29 my ($self, $var) = @_;
170 5 100       13 $self->{control} = $var if defined $var;
171 5         17 $self->{control};
172             }
173              
174              
175             =item controllen LENGTH
176              
177             Prepare the ancillary data buffer to receive LENGTH bytes. There is a
178             corresponding C method, but its use is discouraged -- you have to
179             L the C yourself. Instead see L below
180             for convenient access to the control member.
181              
182             =cut
183              
184             sub controllen {
185 7     7 1 38 my ($self, $nlen) = @_;
186 7         22 $self->_set_length("control",$nlen);
187             }
188              
189             =item flags [FLAGS]
190              
191             Get or set the IO::EventMux::Socket::MsgHdr flags, distinct from the L or
192             L flags. Example:
193              
194             $hdr = new IO::EventMux::Socket::MsgHdr (buflen => 512, controllen => 3);
195             recvmsg(IN, $hdr);
196             if ($hdr->flags & MSG_CTRUNC) { # &Socket::MSG_CTRUNC
197             warn "Yikes! Ancillary data was truncated\n";
198             }
199              
200             =cut
201              
202             sub flags {
203 2     2 1 7 my ($self, $var) = @_;
204 2 100       8 $self->{flags} = $var if defined $var;
205 2         9 $self->{flags};
206             }
207              
208             =item cmsghdr LEVEL, TYPE, DATA [ LEVEL, TYPE, DATA ... ]
209              
210             Without arguments, this method returns a list of "LEVEL, TYPE, DATA, ...", or
211             an empty list if there is no ancillary data. With arguments, this method
212             copies and flattens its parameters into the internal control buffer.
213              
214             In any case, DATA is in a message-specific format which likely requires
215             special treatment (packing or unpacking).
216              
217             Examples:
218              
219             my @cmsg = $hdr->cmsghdr();
220             while (my ($level, $type, $data) = splice(@cmsg, 0, 3)) {
221             warn "unknown cmsg LEVEL\n", next unless $level == IPPROTO_IPV6;
222             warn "unknown cmsg TYPE\n", next unless $type == IPV6_PKTINFO;
223             ...
224             }
225              
226             my $data = pack("i" x @filehandles, map {fileno $_} @filehandles);
227             my $hdr->cmsghdr(SOL_SOCKET, SCM_RIGHTS, $data);
228             sendmsg(S, $hdr);
229              
230             =cut
231              
232             sub cmsghdr {
233 5     5 1 71 my $self = shift;
234 5 100       28 unless (@_) { return &unpack_cmsghdr($self->{control}); }
  2         46  
235 3         20 $self->{control} = &pack_cmsghdr(@_);
236             }
237              
238             =item sendmsg SOCKET, MSGHDR
239              
240             =item sendmsg SOCKET, MSGHDR, FLAGS
241              
242             Send a message as described by C MSGHDR over SOCKET,
243             optionally as specified by FLAGS (default 0). MSGHDR should supply
244             at least a I member, and connectionless socket senders might
245             also supply a I member. Ancillary data may be sent via
246             I.
247              
248             Returns number of bytes sent, or undef on failure.
249              
250             =item recvmsg SOCKET, MSGHDR
251              
252             =item recvmsg SOCKET, MSGHDR, FLAGS
253              
254             Receive a message as requested by C MSGHDR from
255             SOCKET, optionally as specified by FLAGS (default 0). The caller
256             requests I bytes in MSGHDR, possibly also recording up to
257             I bytes of the sender's (packed) address and perhaps
258             I bytes of ancillary data.
259              
260             Returns number of bytes received, or undef on failure. I
261             et. al. are updated to reflect the actual lengths of received data.
262              
263             =item pack_cmsghdr
264              
265             =item unpack_cmsghdr
266              
267             =cut
268              
269             require XSLoader;
270             XSLoader::load('IO::EventMux::Socket::MsgHdr', $VERSION);
271              
272              
273             # Module import
274             # =============
275             #
276             sub import {
277 3     3   42 require Exporter;
278 3         342860 goto &Exporter::import;
279             }
280              
281             sub _set_length {
282 26     26   39 my ($self, $attr, $nlen) = @_;
283 26   100     120 my $olen = length($self->{$attr} or '');
284 26 100       98 return $olen unless defined $nlen;
285            
286 17 50       41 if ($nlen != $olen) {
287 17 50       134 $self->{$attr} = $olen > $nlen
288             ? substr($self->{$attr}, 0, $nlen)
289             : "\x00" x $nlen;
290             }
291 17         51 return $nlen;
292             }
293              
294             =item B
295              
296             Read "MSG_ERRQUEUE" errors on socket and decode ICMP error msg
297              
298             =cut
299              
300             sub socket_errors {
301 0     0 1   my ($sock) = @_;
302            
303 0           my @results;
304 0           my $msgHdr = new IO::EventMux::Socket::MsgHdr(
305             buflen => 512,
306             controllen => 256,
307             namelen => 16,
308             );
309            
310             # Copy errors to msgHdr
311 0           my $old_errno = $!;
312 0           my $rv = recvmsg($sock, $msgHdr, MSG_ERRQUEUE);
313 0 0         if(not defined $rv) {
314 0 0 0       if($old_errno != $! and $! != EAGAIN) {
315 0           print "error(socket_errors):$!\n";
316             }
317 0           return;
318             }
319            
320             # Unpack errors
321 0           my @cmsg = $msgHdr->cmsghdr();
322 0           while (my ($level, $type, $data) = splice(@cmsg, 0, 3)) {
323 0 0 0       if($level == SOL_IP and $type == IP_RECVERR) {
324 0           my ($from, $dst_ip, $dst_port, $pkt);
325              
326             # struct sock_extended_err from man recvmsg
327 0           my ($ee_errno, $ee_origin, $ee_type, $ee_code, $ee_pad,
328             $ee_info, $ee_data, $ee_other) = unpack("ICCCCIIa*", $data);
329            
330 0 0         if($ee_origin == SO_EE_ORIGIN_NONE) {
    0          
    0          
    0          
331 0           print "error(socket_errors): origin is none??\n";
332 0           next;
333            
334             } elsif($ee_origin == SO_EE_ORIGIN_LOCAL) {
335 0           $from = 'localhost';
336              
337             } elsif($ee_origin == SO_EE_ORIGIN_ICMP) {
338             # Get offender ip($from)(the one who sent the ICMP message)
339             # and $dst_ip and $dst_port from packet in ICMP packet.
340 0           ($from, $dst_ip, $dst_port) = (
341             inet_ntoa((unpack_sockaddr_in($ee_other))[1]),
342             inet_ntoa((unpack_sockaddr_in($msgHdr->name))[1]),
343             (unpack_sockaddr_in($msgHdr->name))[0]
344             );
345            
346             # Get what's left of the packet
347 0           $pkt = $msgHdr->buf;
348            
349             } elsif($ee_origin == SO_EE_ORIGIN_ICMP6) {
350 0           die "IPv6 not supported, patches welcome";
351             }
352              
353 0 0 0       if($ee_errno == ECONNREFUSED) {
    0 0        
    0 0        
      0        
354 0           push(@results, {
355             type => 'error',
356             errno => $ee_errno,
357             error => strerror($ee_errno),
358             from => $from,
359             dst_ip => $dst_ip,
360             dst_port => $dst_port,
361             data => $pkt,
362             fh => $sock,
363             });
364             } elsif($ee_errno == EMSGSIZE) {
365 0           push(@results, {
366             type => 'error',
367             errno => $ee_errno,
368             error => strerror($ee_errno),
369             mtu => $ee_info,
370             fh => $sock,
371             });
372             } elsif($ee_errno == ETIMEDOUT or $ee_errno == EPROTO
373             or $ee_errno == EHOSTUNREACH or $ee_errno == ENETUNREACH
374             or $ee_errno == EACCES) {
375 0           push(@results, {
376             type => 'error',
377             fh => $sock,
378             errno => $ee_errno,
379             error => strerror($ee_errno),
380             });
381             } else {
382 0           push(@results, {
383             type => 'error',
384             fh => $sock,
385             errno => $ee_errno,
386             error => strerror($ee_errno),
387             });
388             }
389            
390             } else {
391 0           print "error(socket_errors): unknown type: $type and/or $level\n";
392             }
393             }
394 0           return @results;
395             }
396              
397             =back
398              
399             =head1 EXPORT
400              
401             C exports L and L by default into the
402             caller's namespace, and in any case these methods into the IO::Socket
403             namespace.
404              
405             =head2 BUGS
406              
407             The underlying XS presently makes use of RFC 2292 CMSG_* manipulation macros,
408             which may not be available on all systems supporting sendmsg/recvmsg as known
409             to 4.3BSD Reno/POSIX.1g. Older C definitions with
410             C members (instead of C) are not supported at all.
411              
412             There is no Socket::CMsgHdr, which may be a good thing. Examples are meager,
413             see the t/ directory for send(to) and recv(from) emulations in terms of this
414             module.
415              
416             =head1 SEE ALSO
417              
418             L, L, L<"RFC 2292">
419              
420             =head1 AUTHOR
421              
422             Troels Liebe Bentsen
423              
424             =head1 COPYRIGHT AND LICENSE
425              
426             Copyright(C) 2007-2008 by Troels Liebe Bentsen
427             Copyright(C) 2003 by Michael J. Pomraning
428              
429             This library is free software; you can redistribute it and/or modify
430             it under the same terms as Perl itself.
431              
432             =cut
433              
434             1;