Thanks. I guess what will happen is that the hardcoded limit will just be increased in Perl core code.
However I wanted to be able to retrieve the full TCP_INFO structure even when using older Perl versions... So regarding my original question "what can I do to retrieve the full TCP_INFO structure ?", here is the workaround I came up with, which seems to be working fine according to first results:
use constant {
DARWIN_SYS_getsockopt => 118, # from bsd/kern/syscalls.master
GETSOCKOPT_MAXLEN => 512, # enough for now I guess...
};
sub darwin_getsockopt {
my $optval = "\0" x GETSOCKOPT_MAXLEN;
my $optlen=pack('i',GETSOCKOPT_MAXLEN);
my $rv=syscall(DARWIN_SYS_getsockopt,fileno($_[0]),$_[1],$_[2],$optv
+al,$optlen);
return $rv < 0 ? undef : substr($optval,0,unpack('i',$optlen));
}
Here is a revised version of the test program, using the workaround when run on macOS:
use Socket qw'PF_INET SOCK_STREAM IPPROTO_TCP inet_aton sockaddr_in';
use constant {
DARWIN_TCP_INFO => 0x200, # from bsd/netinet/tcp.h
DARWIN_SYS_getsockopt => 118, # from bsd/kern/syscalls.master
GETSOCKOPT_MAXLEN => 512, # enough for now I guess...
};
sub darwin_getsockopt {
my $optval = "\0" x GETSOCKOPT_MAXLEN;
my $optlen=pack('i',GETSOCKOPT_MAXLEN);
my $rv=syscall(DARWIN_SYS_getsockopt,fileno($_[0]),$_[1],$_[2],$optv
+al,$optlen);
return $rv < 0 ? undef : substr($optval,0,unpack('i',$optlen));
}
my $GETSOCKOPT_FUNC = $^O eq 'darwin' ? \&darwin_getsockopt : \&CORE::
+getsockopt;
my $TCP_INFO = ($^O eq 'darwin' ? DARWIN_TCP_INFO : eval { Socket::TCP
+_INFO() })
or die "This system doesn't support the TCP_INFO structure.\n";
my ($testHost,$testPort)=('perl.org',443);
socket(my $sock, PF_INET, SOCK_STREAM, IPPROTO_TCP)
or die "Could not create socket - $!\n";
my $iaddr=inet_aton($testHost);
my $paddr=sockaddr_in($testPort,$iaddr);
connect($sock,$paddr)
or die "Failed to connect to $testHost:$testPort - $!\n";
my $tcpInfoData=$GETSOCKOPT_FUNC->($sock,IPPROTO_TCP,$TCP_INFO)
or die "Error while calling getsockopt - $!\n";
my $tcpInfoLength=length($tcpInfoData);
if($tcpInfoLength < 256) {
print "This system doesn't have a TCP_INFO structure large enough to
+ reproduce the problem.\n";
}elsif($tcpInfoLength == 256) {
print "The TCP_INFO structure seems to be truncated to 256 bytes on
+this system.\n";
}else{
print "This system doesn't seem to be affected by the problem (TCP_I
+NFO length: $tcpInfoLength).\n";
}
And finally, here is another implementation of the workaround, using a more generic approach to let the user specify a buffer length if needed (optional argument), the ideal solution in my opinion (if it was implemented in Perl core to be more efficient):
sub getsockopt_darwin_gen {
return &CORE::getsockopt if(@_ < 4);
my $optlen = pop;
my $optval = "\0" x $optlen;
$optlen=pack('i',$optlen);
my $rv=syscall(DARWIN_SYS_getsockopt,fileno($_[0]),$_[1],$_[2],$optv
+al,$optlen);
return $rv < 0 ? undef : substr($optval,0,unpack('i',$optlen));
}
|