Skip Menu |

This queue is for tickets about the Cache-Memcached CPAN distribution.

Report information
The Basics
Id: 50577
Status: resolved
Priority: 0/
Queue: Cache-Memcached

People
Owner: Nobody in particular
Requestors: troy [...] good.net
Cc:
AdminCc:

Bug Information
Severity: Normal
Broken in:
  • 1.0.10
  • 1.0.11
  • 1.0.12
  • 1.13
  • 1.14
  • 1.15
  • 1.16
  • 1.17
  • 1.18
  • 1.20
  • 1.21
  • 1.22
  • 1.23
  • 1.24
  • 1.25
  • 1.26
  • 1.27
Fixed in: (no value)



Subject: Patch for IPv6 support in Cache::Memcached 1.27
memcached supports IPv6 sockets, but the perl client isn't IPv6-aware. Patch is included to make Cache::Memcached IPv6-aware, while falling back gracefully on clients that do not have Socket6.pm. Thanks!
Subject: Cache-Memcached-1.27-ipv6.patch
--- Memcached.pm.old 2009-10-16 15:23:14.000000000 -0700 +++ Memcached.pm 2009-10-16 15:24:34.000000000 -0700 @@ -36,7 +36,7 @@ use constant COMPRESS_SAVINGS => 0.20; # percent use vars qw($VERSION $HAVE_ZLIB $FLAG_NOSIGNAL); -$VERSION = "1.27"; +$VERSION = "1.27.4663"; BEGIN { $HAVE_ZLIB = eval "use Compress::Zlib (); 1;"; @@ -231,7 +231,9 @@ return $cache_sock{$host} if $cache_sock{$host}; my $now = time(); - my ($ip, $port) = $host =~ /(.*):(\d+)/; + my ($ip, $port) = $host =~ /(.*):(\d+)$/; + $ip =~ s/[\[\]]//g; # get rid of optional IPv6 brackets + return undef if $host_dead{$host} && $host_dead{$host} > $now; my $sock; @@ -244,10 +246,24 @@ { # if a preferred IP is known, try that first. if ($self && $self->{pref_ip}{$ip}) { - socket($sock, PF_INET, SOCK_STREAM, $proto); - $sock_map{$sock} = $host; + my $v6ok; my $prefip = $self->{pref_ip}{$ip}; - $sin = Socket::sockaddr_in($port,Socket::inet_aton($prefip)); + if (index($prefip,':')) { # Try IPv6 + eval { + use Socket6 qw(AF_INET6 PF_INET6); + socket($sock, PF_INET6, SOCK_STREAM, $proto); + $sock_map{$sock} = $host; + $sin = Socket6::pack_sockaddr_in6($port,Socket6::inet_pton(AF_INET6,$prefip)); + $v6ok = 1; + }; + } + + unless ($v6ok) { + socket($sock, PF_INET, SOCK_STREAM, $proto); + $sock_map{$sock} = $host; + $sin = Socket::sockaddr_in($port,Socket::inet_aton($prefip)); + } + if (_connect_sock($sock,$sin,$self->{connect_timeout})) { $connected = 1; } else { @@ -260,9 +276,23 @@ # normal path, or fallback path if preferred IP failed unless ($connected) { - socket($sock, PF_INET, SOCK_STREAM, $proto); - $sock_map{$sock} = $host; - $sin = Socket::sockaddr_in($port,Socket::inet_aton($ip)); + my $v6ok; + if (index($ip,':')) { # Try IPv6 + eval { + use Socket6 qw(AF_INET6 PF_INET6); + socket($sock, PF_INET6, SOCK_STREAM, $proto); + $sock_map{$sock} = $host; + $sin = Socket6::pack_sockaddr_in6($port,Socket6::inet_pton(AF_INET6,$ip)); + $v6ok = 1; + }; + } + + unless ($v6ok) { + socket($sock, PF_INET, SOCK_STREAM, $proto); + $sock_map{$sock} = $host; + $sin = Socket::sockaddr_in($port,Socket::inet_aton($ip)); + } + my $timeout = $self ? $self->{connect_timeout} : 0.25; unless (_connect_sock($sock,$sin,$timeout)) { my $cb = $self ? $self->{cb_connect_fail} : undef;
Oops, reuploading as .diff so it should show inside ticket.
--- Memcached.pm.old 2009-10-16 15:23:14.000000000 -0700 +++ Memcached.pm 2009-10-16 15:24:34.000000000 -0700 @@ -36,7 +36,7 @@ use constant COMPRESS_SAVINGS => 0.20; # percent use vars qw($VERSION $HAVE_ZLIB $FLAG_NOSIGNAL); -$VERSION = "1.27"; +$VERSION = "1.27.4663"; BEGIN { $HAVE_ZLIB = eval "use Compress::Zlib (); 1;"; @@ -231,7 +231,9 @@ return $cache_sock{$host} if $cache_sock{$host}; my $now = time(); - my ($ip, $port) = $host =~ /(.*):(\d+)/; + my ($ip, $port) = $host =~ /(.*):(\d+)$/; + $ip =~ s/[\[\]]//g; # get rid of optional IPv6 brackets + return undef if $host_dead{$host} && $host_dead{$host} > $now; my $sock; @@ -244,10 +246,24 @@ { # if a preferred IP is known, try that first. if ($self && $self->{pref_ip}{$ip}) { - socket($sock, PF_INET, SOCK_STREAM, $proto); - $sock_map{$sock} = $host; + my $v6ok; my $prefip = $self->{pref_ip}{$ip}; - $sin = Socket::sockaddr_in($port,Socket::inet_aton($prefip)); + if (index($prefip,':')) { # Try IPv6 + eval { + use Socket6 qw(AF_INET6 PF_INET6); + socket($sock, PF_INET6, SOCK_STREAM, $proto); + $sock_map{$sock} = $host; + $sin = Socket6::pack_sockaddr_in6($port,Socket6::inet_pton(AF_INET6,$prefip)); + $v6ok = 1; + }; + } + + unless ($v6ok) { + socket($sock, PF_INET, SOCK_STREAM, $proto); + $sock_map{$sock} = $host; + $sin = Socket::sockaddr_in($port,Socket::inet_aton($prefip)); + } + if (_connect_sock($sock,$sin,$self->{connect_timeout})) { $connected = 1; } else { @@ -260,9 +276,23 @@ # normal path, or fallback path if preferred IP failed unless ($connected) { - socket($sock, PF_INET, SOCK_STREAM, $proto); - $sock_map{$sock} = $host; - $sin = Socket::sockaddr_in($port,Socket::inet_aton($ip)); + my $v6ok; + if (index($ip,':')) { # Try IPv6 + eval { + use Socket6 qw(AF_INET6 PF_INET6); + socket($sock, PF_INET6, SOCK_STREAM, $proto); + $sock_map{$sock} = $host; + $sin = Socket6::pack_sockaddr_in6($port,Socket6::inet_pton(AF_INET6,$ip)); + $v6ok = 1; + }; + } + + unless ($v6ok) { + socket($sock, PF_INET, SOCK_STREAM, $proto); + $sock_map{$sock} = $host; + $sin = Socket::sockaddr_in($port,Socket::inet_aton($ip)); + } + my $timeout = $self ? $self->{connect_timeout} : 0.25; unless (_connect_sock($sock,$sin,$timeout)) { my $cb = $self ? $self->{cb_connect_fail} : undef;
Wonderful! I'm totally supportive of patches adding IPv6 support, so I'm glad you did this. One concern, though, before we commit this: What if the user doesn't have Socket6? The code should be more tolerant of that. You included Socket6 like this: $ perl -e 'eval { use NonExist; }' Can't locate NonExist.pm in @INC Can you rework that to something like this instead: BEGIN { $HAVE_SOCKET6 = eval "use Socket6; 1;"; } Then just check if ($HAVE_SOCKET6) when needed? Thanks!
Whoops. I guess I should have tested it w/o Socket6.pm :) Did so this time, and it works against IPv6 and IPv4 servers. Thanks!
--- Memcached.pm.old 2009-10-16 15:23:14.000000000 -0700 +++ Memcached.pm 2009-10-21 13:53:06.000000000 -0700 @@ -35,11 +35,12 @@ # size savings required before saving compressed value use constant COMPRESS_SAVINGS => 0.20; # percent -use vars qw($VERSION $HAVE_ZLIB $FLAG_NOSIGNAL); -$VERSION = "1.27"; +use vars qw($VERSION $HAVE_ZLIB $FLAG_NOSIGNAL $HAVE_SOCKET6); +$VERSION = "1.27.4664"; BEGIN { $HAVE_ZLIB = eval "use Compress::Zlib (); 1;"; + $HAVE_SOCKET6 = eval "use Socket6 qw(AF_INET6 PF_INET6); 1;"; } my $HAVE_XS = eval "use Cache::Memcached::GetParserXS; 1;"; @@ -231,7 +232,9 @@ return $cache_sock{$host} if $cache_sock{$host}; my $now = time(); - my ($ip, $port) = $host =~ /(.*):(\d+)/; + my ($ip, $port) = $host =~ /(.*):(\d+)$/; + $ip =~ s/[\[\]]//g; # get rid of optional IPv6 brackets + return undef if $host_dead{$host} && $host_dead{$host} > $now; my $sock; @@ -244,10 +247,18 @@ { # if a preferred IP is known, try that first. if ($self && $self->{pref_ip}{$ip}) { - socket($sock, PF_INET, SOCK_STREAM, $proto); - $sock_map{$sock} = $host; my $prefip = $self->{pref_ip}{$ip}; - $sin = Socket::sockaddr_in($port,Socket::inet_aton($prefip)); + if (index($prefip,':') && $HAVE_SOCKET6) { + no strict; # The constants PF_INET6 and AF_INET6 won't have been imported without Socket6.pm + socket($sock, PF_INET6, SOCK_STREAM, $proto); + $sock_map{$sock} = $host; + $sin = Socket6::pack_sockaddr_in6($port,Socket6::inet_pton(AF_INET6,$prefip)); + } else { + socket($sock, PF_INET, SOCK_STREAM, $proto); + $sock_map{$sock} = $host; + $sin = Socket::sockaddr_in($port,Socket::inet_aton($prefip)); + } + if (_connect_sock($sock,$sin,$self->{connect_timeout})) { $connected = 1; } else { @@ -260,9 +271,17 @@ # normal path, or fallback path if preferred IP failed unless ($connected) { - socket($sock, PF_INET, SOCK_STREAM, $proto); - $sock_map{$sock} = $host; - $sin = Socket::sockaddr_in($port,Socket::inet_aton($ip)); + if (index($ip,':') && $HAVE_SOCKET6) { + no strict; + socket($sock, PF_INET6, SOCK_STREAM, $proto); + $sock_map{$sock} = $host; + $sin = Socket6::pack_sockaddr_in6($port,Socket6::inet_pton(AF_INET6,$ip)); + } else { + socket($sock, PF_INET, SOCK_STREAM, $proto); + $sock_map{$sock} = $host; + $sin = Socket::sockaddr_in($port,Socket::inet_aton($ip)); + } + my $timeout = $self ? $self->{connect_timeout} : 0.25; unless (_connect_sock($sock,$sin,$timeout)) { my $cb = $self ? $self->{cb_connect_fail} : undef;
Comitted in svn 834 and uploaded to CPAN as Cache-Memcached-1.28.tar.gz. SVN, btw: http://code.sixapart.com/svn/memcached/trunk/api/perl