From: Paul Evans Date: Thu, 25 Nov 2010 20:06:36 +0000 (+0000) Subject: [PATCH 1/3] Implement Socket::pack_sockaddr_in6() and unpack_sockaddr_in6() X-Git-Tag: accepted/trunk/20130322.191538~6587^2~22 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=c73aa44c20991e800d9dcc1f8c59404c77ce882e;p=platform%2Fupstream%2Fperl.git [PATCH 1/3] Implement Socket::pack_sockaddr_in6() and unpack_sockaddr_in6() Signed-off-by: Chris 'BinGOs' Williams --- diff --git a/ext/Socket/Socket.pm b/ext/Socket/Socket.pm index da70114..f1d80e8 100644 --- a/ext/Socket/Socket.pm +++ b/ext/Socket/Socket.pm @@ -147,6 +147,21 @@ representing the IP address (you can use inet_ntoa() to convert the address to the four-dotted numeric format). Will croak if the structure does not have AF_INET in the right place. +=item pack_sockaddr_in6 PORT, IP6_ADDRESS, [ SCOPE_ID, [ FLOWINFO ] ] + +Takes two to four arguments, a port number, an opaque string (as returned by +inet_pton()), optionally a scope ID number, and optionally a flow label +number. Returns the sockaddr_in6 structure with those arguments packed in +with AF_INET6 filled in. IPv6 equivalent of pack_sockaddr_in(). + +=item unpack_sockaddr_in6 SOCKADDR_IN6 + +Takes a sockaddr_in6 structure (as returned by pack_sockaddr_in6()) and +returns an array of four elements: the port number, an opaque string +representing the IPv6 address, the scope ID, and the flow label. (You can +use inet_ntop() to convert the address to the usual string format). Will +croak if the structure does not have AF_INET6 in the right place. + =item sockaddr_un PATHNAME =item sockaddr_un SOCKADDR_UN @@ -205,6 +220,7 @@ require XSLoader; sockaddr_family pack_sockaddr_in unpack_sockaddr_in pack_sockaddr_un unpack_sockaddr_un + pack_sockaddr_in6 unpack_sockaddr_in6 sockaddr_in sockaddr_un INADDR_ANY INADDR_BROADCAST INADDR_LOOPBACK INADDR_NONE AF_802 diff --git a/ext/Socket/Socket.xs b/ext/Socket/Socket.xs index 8d219c4..ce6ec34 100644 --- a/ext/Socket/Socket.xs +++ b/ext/Socket/Socket.xs @@ -455,6 +455,64 @@ unpack_sockaddr_in(sin_sv) } void +pack_sockaddr_in6(port, sin6_addr, scope_id=0, flowinfo=0) + unsigned short port + SV * sin6_addr + unsigned long scope_id + unsigned long flowinfo + CODE: + { +#ifdef AF_INET6 + struct sockaddr_in6 sin6; + char * addrbytes; + STRLEN addrlen; + if (DO_UTF8(sin6_addr) && !sv_utf8_downgrade(sin6_addr, 1)) + croak("Wide character in %s", "Socket::pack_sockaddr_in6"); + addrbytes = SvPVbyte(sin6_addr, addrlen); + if(addrlen != sizeof(sin6.sin6_addr)) + croak("Bad arg length %s, length is %d, should be %d", + "Socket::pack_sockaddr_in6", addrlen, sizeof(sin6.sin6_addr)); + Zero(&sin6, sizeof(sin6), char); + sin6.sin6_family = AF_INET6; + sin6.sin6_port = htons(port); + sin6.sin6_flowinfo = htonl(flowinfo); + Copy(addrbytes, &sin6.sin6_addr, sizeof(sin6.sin6_addr), char); + sin6.sin6_scope_id = scope_id; + ST(0) = newSVpvn_flags((char *)&sin6, sizeof(sin6), SVs_TEMP); +#else + ST(0) = (SV*)not_here("pack_sockaddr_in6"); +#endif + } + +void +unpack_sockaddr_in6(sin6_sv) + SV * sin6_sv + PPCODE: + { +#ifdef AF_INET6 + STRLEN addrlen; + struct sockaddr_in6 sin6; + char * addrbytes = SvPVbyte(sin6_sv, addrlen); + if (addrlen != sizeof(sin6)) + croak("Bad arg length for %s, length is %d, should be %d", + "Socket::unpack_sockaddr_in6", + addrlen, sizeof(sin6)); + Copy(addrbytes, &sin6, sizeof(sin6), char); + if(sin6.sin6_family != AF_INET6) + croak("Bad address family for %s, got %d, should be %d", + "Socket::unpack_sockaddr_in6", + sin6.sin6_family, AF_INET6); + EXTEND(SP, 4); + mPUSHi(ntohs(sin6.sin6_port)); + mPUSHp((char *)&sin6.sin6_addr, sizeof(sin6.sin6_addr)); + mPUSHi(sin6.sin6_scope_id); + mPUSHi(ntohl(sin6.sin6_flowinfo)); +#else + ST(0) = (SV*)not_here("pack_sockaddr_in6"); +#endif + } + +void inet_ntop(af, ip_address_sv) int af SV * ip_address_sv diff --git a/ext/Socket/t/Socket.t b/ext/Socket/t/Socket.t index 9a6d31f..3cfd840 100644 --- a/ext/Socket/t/Socket.t +++ b/ext/Socket/t/Socket.t @@ -12,7 +12,7 @@ BEGIN { use Socket qw(:all); -print "1..21\n"; +print "1..26\n"; $has_echo = $^O ne 'MSWin32'; $alarmed = 0; @@ -184,3 +184,25 @@ if($Config{d_inetntop} && $Config{d_inetaton}){ # no IPv6 print "ok $_ - skipped on this platform\n" for 19 .. 21; } + +if(defined eval { AF_INET6() } ) { + my $sin6 = pack_sockaddr_in6(0x1234, "0123456789abcdef", 567, 89); + + print "not " unless sockaddr_family($sin6) == AF_INET6; + print "ok 22\n"; + + print "not " unless (unpack_sockaddr_in6($sin6))[0] == 0x1234; + print "ok 23\n"; + + print "not " unless (unpack_sockaddr_in6($sin6))[1] == "0123456789abcdef"; + print "ok 24\n"; + + print "not " unless (unpack_sockaddr_in6($sin6))[2] == 567; + print "ok 25\n"; + + print "not " unless (unpack_sockaddr_in6($sin6))[3] == 89; + print "ok 26\n"; +} +else { + print "ok $_ - skipped - no AF_INET6\n" for 22 .. 26; +}