[PATCH 1/3] Implement Socket::pack_sockaddr_in6() and unpack_sockaddr_in6()
authorPaul Evans <leonerd@leonerd.org.uk>
Thu, 25 Nov 2010 20:06:36 +0000 (20:06 +0000)
committerChris 'BinGOs' Williams <chris@bingosnet.co.uk>
Thu, 25 Nov 2010 20:06:36 +0000 (20:06 +0000)
Signed-off-by: Chris 'BinGOs' Williams <chris@bingosnet.co.uk>
ext/Socket/Socket.pm
ext/Socket/Socket.xs
ext/Socket/t/Socket.t

index da70114..f1d80e8 100644 (file)
@@ -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
index 8d219c4..ce6ec34 100644 (file)
@@ -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
index 9a6d31f..3cfd840 100644 (file)
@@ -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;
+}